1 #include "report_manager.hpp" 2 3 #include "interfaces/types.hpp" 4 #include "report.hpp" 5 #include "utils/conversion.hpp" 6 #include "utils/transform.hpp" 7 8 #include <phosphor-logging/log.hpp> 9 #include <sdbusplus/exception.hpp> 10 11 #include <stdexcept> 12 #include <system_error> 13 14 ReportManager::ReportManager( 15 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 16 std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 17 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 18 reportFactory(std::move(reportFactoryIn)), 19 reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 20 { 21 reports.reserve(maxReports); 22 23 loadFromPersistent(); 24 25 reportManagerIface = objServer->add_unique_interface( 26 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 27 dbusIface.register_property_r( 28 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_, 29 [](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(); }); 33 34 dbusIface.register_method( 35 "AddReport", [this](boost::asio::yield_context& yield, 36 const std::string& reportName, 37 const std::string& reportingType, 38 const bool emitsReadingsUpdate, 39 const bool logToMetricReportsCollection, 40 const uint64_t interval, 41 ReadingParameters metricParams) { 42 return addReport(yield, reportName, reportingType, 43 emitsReadingsUpdate, 44 logToMetricReportsCollection, 45 std::chrono::milliseconds(interval), 46 std::move(metricParams)) 47 .getPath(); 48 }); 49 }); 50 } 51 52 void ReportManager::removeReport(const interfaces::Report* report) 53 { 54 reports.erase( 55 std::remove_if(reports.begin(), reports.end(), 56 [report](const auto& x) { return report == x.get(); }), 57 reports.end()); 58 } 59 60 void ReportManager::verifyAddReport(const std::string& reportName, 61 const std::string& reportingType, 62 std::chrono::milliseconds interval, 63 const ReadingParameters& readingParams) 64 { 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 81 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) 91 { 92 throw sdbusplus::exception::SdBusError( 93 static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 94 } 95 96 if (readingParams.size() > maxReadingParams) 97 98 { 99 throw sdbusplus::exception::SdBusError( 100 static_cast<int>(std::errc::argument_list_too_long), 101 "Too many reading parameters"); 102 } 103 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 } 116 } 117 118 interfaces::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 { 124 verifyAddReport(reportName, reportingType, interval, metricParams); 125 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 133 interfaces::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 { 139 auto metricParams = utils::transform( 140 labeledMetricParams, [](const LabeledMetricParameters& param) { 141 using namespace utils::tstring; 142 143 return ReadingParameters::value_type( 144 sdbusplus::message::object_path( 145 param.at_index<0>().at_label<Path>()), 146 utils::enumToString(param.at_index<1>()), param.at_index<2>(), 147 param.at_index<3>()); 148 }); 149 150 verifyAddReport(reportName, reportingType, interval, metricParams); 151 152 reports.emplace_back(reportFactory->make( 153 reportName, reportingType, emitsReadingsUpdate, 154 logToMetricReportsCollection, interval, std::move(metricParams), *this, 155 *reportStorage, labeledMetricParams)); 156 return *reports.back(); 157 } 158 159 void 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>(); 182 auto readingParameters = 183 data->at("ReadingParameters") 184 .get<std::vector<LabeledMetricParameters>>(); 185 186 addReport(name, reportingType, emitsReadingsSignal, 187 logToMetricReportsCollection, 188 std::chrono::milliseconds(interval), 189 std::move(readingParameters)); 190 } 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( 196 "FILENAME=%s", 197 static_cast<std::filesystem::path>(path).c_str()), 198 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 199 reportStorage->remove(path); 200 } 201 } 202 } 203 204 void 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 } 215