1 #include "report_manager.hpp" 2 3 #include "report.hpp" 4 5 #include <phosphor-logging/log.hpp> 6 #include <sdbusplus/exception.hpp> 7 8 #include <stdexcept> 9 #include <system_error> 10 11 ReportManager::ReportManager( 12 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 13 std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 14 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 15 reportFactory(std::move(reportFactoryIn)), 16 reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 17 { 18 reports.reserve(maxReports); 19 20 loadFromPersistent(); 21 22 reportManagerIface = objServer->add_unique_interface( 23 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 24 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(); }); 30 31 dbusIface.register_method( 32 "AddReport", [this](boost::asio::yield_context& yield, 33 const std::string& reportName, 34 const std::string& reportingType, 35 const bool emitsReadingsUpdate, 36 const bool logToMetricReportsCollection, 37 const uint64_t interval, 38 const ReadingParameters& metricParams) { 39 return addReport(yield, reportName, reportingType, 40 emitsReadingsUpdate, 41 logToMetricReportsCollection, 42 std::chrono::milliseconds(interval), 43 metricParams) 44 ->getPath(); 45 }); 46 }); 47 } 48 49 void ReportManager::removeReport(const interfaces::Report* report) 50 { 51 reports.erase( 52 std::remove_if(reports.begin(), reports.end(), 53 [report](const auto& x) { return report == x.get(); }), 54 reports.end()); 55 } 56 57 std::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 92 void 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 } 138