blob: eb2d76720a3602cd4fd66c63491f8db94c8f5f6e [file] [log] [blame]
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02001#include "report_manager.hpp"
2
Wludzik, Jozefe2362792020-10-27 17:23:55 +01003#include "report.hpp"
4
5#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02006#include <sdbusplus/exception.hpp>
7
Wludzik, Jozefe2362792020-10-27 17:23:55 +01008#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02009#include <system_error>
10
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020011ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020012 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010013 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020014 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020015 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010016 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020017{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020018 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010019
Wludzik, Jozefe2362792020-10-27 17:23:55 +010020 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020021
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020022 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020023 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020024 dbusIface.register_property_r(
25 "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_,
26 [](const auto&) { return maxReports; });
27 dbusIface.register_property_r(
28 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
29 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020030
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020031 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010032 "AddReport", [this](boost::asio::yield_context& yield,
33 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020034 const std::string& reportingType,
35 const bool emitsReadingsUpdate,
36 const bool logToMetricReportsCollection,
37 const uint64_t interval,
38 const ReadingParameters& metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010039 return addReport(yield, reportName, reportingType,
40 emitsReadingsUpdate,
41 logToMetricReportsCollection,
42 std::chrono::milliseconds(interval),
43 metricParams)
44 ->getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020045 });
46 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020047}
48
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020049void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020050{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020051 reports.erase(
52 std::remove_if(reports.begin(), reports.end(),
53 [report](const auto& x) { return report == x.get(); }),
54 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020055}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010056
57std::unique_ptr<interfaces::Report>& ReportManager::addReport(
58 std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
59 const std::string& reportName, const std::string& reportingType,
60 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
61 std::chrono::milliseconds interval, const ReadingParameters& metricParams)
62{
63 if (reports.size() >= maxReports)
64 {
65 throw sdbusplus::exception::SdBusError(
66 static_cast<int>(std::errc::too_many_files_open),
67 "Reached maximal report count");
68 }
69
70 for (const auto& report : reports)
71 {
72 if (report->getName() == reportName)
73 {
74 throw sdbusplus::exception::SdBusError(
75 static_cast<int>(std::errc::file_exists), "Duplicate report");
76 }
77 }
78
79 if (interval < minInterval)
80 {
81 throw sdbusplus::exception::SdBusError(
82 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
83 }
84
85 reports.emplace_back(
86 reportFactory->make(yield, reportName, reportingType,
87 emitsReadingsUpdate, logToMetricReportsCollection,
88 interval, metricParams, *this, *reportStorage));
89 return reports.back();
90}
91
92void ReportManager::loadFromPersistent()
93{
94 std::vector<interfaces::JsonStorage::FilePath> paths =
95 reportStorage->list();
96
97 for (const auto& path : paths)
98 {
99 std::optional<nlohmann::json> data = reportStorage->load(path);
100 try
101 {
102 size_t version = data->at("Version").get<size_t>();
103 if (version != Report::reportVersion)
104 {
105 throw std::logic_error("Invalid version");
106 }
107 std::string& name = data->at("Name").get_ref<std::string&>();
108 std::string& reportingType =
109 data->at("ReportingType").get_ref<std::string&>();
110 bool emitsReadingsSignal =
111 data->at("EmitsReadingsUpdate").get<bool>();
112 bool logToMetricReportsCollection =
113 data->at("LogToMetricReportsCollection").get<bool>();
114 uint64_t interval = data->at("Interval").get<uint64_t>();
115 ReadingParameters readingParameters;
116 for (auto& item : data->at("ReadingParameters"))
117 {
118 readingParameters.emplace_back(
119 LabeledReadingParameter::from_json(item));
120 }
121
122 addReport(std::nullopt, name, reportingType, emitsReadingsSignal,
123 logToMetricReportsCollection,
124 std::chrono::milliseconds(interval), readingParameters);
125 }
126 catch (const std::exception& e)
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "Failed to load report from storage",
130 phosphor::logging::entry(
131 "filename=",
132 static_cast<std::filesystem::path>(path).c_str()),
133 phosphor::logging::entry("msg=", e.what()));
134 reportStorage->remove(path);
135 }
136 }
137}