1 #include "report_manager.hpp" 2 3 #include "interfaces/types.hpp" 4 #include "report.hpp" 5 #include "utils/transform.hpp" 6 7 #include <phosphor-logging/log.hpp> 8 #include <sdbusplus/exception.hpp> 9 10 #include <stdexcept> 11 #include <system_error> 12 13 ReportManager::ReportManager( 14 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 15 std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 16 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 17 reportFactory(std::move(reportFactoryIn)), 18 reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 19 { 20 reports.reserve(maxReports); 21 22 loadFromPersistent(); 23 24 reportManagerIface = objServer->add_unique_interface( 25 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 26 dbusIface.register_property_r( 27 "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_, 28 [](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(); }); 32 33 dbusIface.register_method( 34 "AddReport", [this](boost::asio::yield_context& yield, 35 const std::string& reportName, 36 const std::string& reportingType, 37 const bool emitsReadingsUpdate, 38 const bool logToMetricReportsCollection, 39 const uint64_t interval, 40 ReadingParameters metricParams) { 41 return addReport(yield, reportName, reportingType, 42 emitsReadingsUpdate, 43 logToMetricReportsCollection, 44 std::chrono::milliseconds(interval), 45 std::move(metricParams)) 46 .getPath(); 47 }); 48 }); 49 } 50 51 void ReportManager::removeReport(const interfaces::Report* report) 52 { 53 reports.erase( 54 std::remove_if(reports.begin(), reports.end(), 55 [report](const auto& x) { return report == x.get(); }), 56 reports.end()); 57 } 58 59 void ReportManager::verifyAddReport(const std::string& reportName, 60 std::chrono::milliseconds interval) 61 { 62 if (reports.size() >= maxReports) 63 { 64 throw sdbusplus::exception::SdBusError( 65 static_cast<int>(std::errc::too_many_files_open), 66 "Reached maximal report count"); 67 } 68 69 for (const auto& report : reports) 70 { 71 if (report->getName() == reportName) 72 { 73 throw sdbusplus::exception::SdBusError( 74 static_cast<int>(std::errc::file_exists), "Duplicate report"); 75 } 76 } 77 78 if (interval < minInterval) 79 { 80 throw sdbusplus::exception::SdBusError( 81 static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 82 } 83 } 84 85 interfaces::Report& ReportManager::addReport( 86 boost::asio::yield_context& yield, const std::string& reportName, 87 const std::string& reportingType, const bool emitsReadingsUpdate, 88 const bool logToMetricReportsCollection, std::chrono::milliseconds interval, 89 ReadingParameters metricParams) 90 { 91 verifyAddReport(reportName, interval); 92 93 reports.emplace_back(reportFactory->make( 94 yield, reportName, reportingType, emitsReadingsUpdate, 95 logToMetricReportsCollection, interval, std::move(metricParams), *this, 96 *reportStorage)); 97 return *reports.back(); 98 } 99 100 interfaces::Report& ReportManager::addReport( 101 const std::string& reportName, const std::string& reportingType, 102 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection, 103 std::chrono::milliseconds interval, 104 std::vector<LabeledMetricParameters> labeledMetricParams) 105 { 106 verifyAddReport(reportName, interval); 107 108 auto metricParams = utils::transform( 109 labeledMetricParams, [](const LabeledMetricParameters& param) { 110 using namespace utils::tstring; 111 112 return ReadingParameters::value_type( 113 utils::transform(param.at_index<0>(), 114 [](const LabeledSensorParameters& p) { 115 return sdbusplus::message::object_path( 116 p.at_label<Path>()); 117 }), 118 param.at_index<1>(), param.at_index<2>(), param.at_index<3>()); 119 }); 120 121 reports.emplace_back(reportFactory->make( 122 reportName, reportingType, emitsReadingsUpdate, 123 logToMetricReportsCollection, interval, std::move(metricParams), *this, 124 *reportStorage, labeledMetricParams)); 125 return *reports.back(); 126 } 127 128 void ReportManager::loadFromPersistent() 129 { 130 std::vector<interfaces::JsonStorage::FilePath> paths = 131 reportStorage->list(); 132 133 for (const auto& path : paths) 134 { 135 std::optional<nlohmann::json> data = reportStorage->load(path); 136 try 137 { 138 size_t version = data->at("Version").get<size_t>(); 139 if (version != Report::reportVersion) 140 { 141 throw std::logic_error("Invalid version"); 142 } 143 std::string& name = data->at("Name").get_ref<std::string&>(); 144 std::string& reportingType = 145 data->at("ReportingType").get_ref<std::string&>(); 146 bool emitsReadingsSignal = 147 data->at("EmitsReadingsUpdate").get<bool>(); 148 bool logToMetricReportsCollection = 149 data->at("LogToMetricReportsCollection").get<bool>(); 150 uint64_t interval = data->at("Interval").get<uint64_t>(); 151 auto readingParameters = 152 data->at("ReadingParameters") 153 .get<std::vector<LabeledMetricParameters>>(); 154 155 addReport(name, reportingType, emitsReadingsSignal, 156 logToMetricReportsCollection, 157 std::chrono::milliseconds(interval), 158 std::move(readingParameters)); 159 } 160 catch (const std::exception& e) 161 { 162 phosphor::logging::log<phosphor::logging::level::ERR>( 163 "Failed to load report from storage", 164 phosphor::logging::entry( 165 "filename=", 166 static_cast<std::filesystem::path>(path).c_str()), 167 phosphor::logging::entry("msg=", e.what())); 168 reportStorage->remove(path); 169 } 170 } 171 } 172