1 #include "report_manager.hpp" 2 3 #include "report.hpp" 4 #include "types/report_types.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 ReadingParameters 15 convertToReadingParameters(ReadingParametersPastVersion params) 16 { 17 return utils::transform(params, [](const auto& param) { 18 using namespace std::chrono_literals; 19 20 return ReadingParameters::value_type( 21 std::vector{{std::get<0>(param)}}, std::get<1>(param), 22 std::get<2>(param), std::get<3>(param), 23 utils::enumToString(CollectionTimeScope::point), 0u); 24 }); 25 } 26 27 ReportManager::ReportManager( 28 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 29 std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 30 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 31 reportFactory(std::move(reportFactoryIn)), 32 reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 33 { 34 reports.reserve(maxReports); 35 36 loadFromPersistent(); 37 38 reportManagerIface = objServer->add_unique_interface( 39 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 40 dbusIface.register_property_r( 41 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_, 42 [](const auto&) { return maxReports; }); 43 dbusIface.register_property_r( 44 "MaxReportNameLength", size_t{}, 45 sdbusplus::vtable::property_::const_, 46 [](const auto&) { return maxReportNameLength; }); 47 dbusIface.register_property_r( 48 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_, 49 [](const auto&) -> uint64_t { return minInterval.count(); }); 50 51 dbusIface.register_method( 52 "AddReport", [this](boost::asio::yield_context& yield, 53 const std::string& reportName, 54 const std::string& reportingType, 55 const bool emitsReadingsUpdate, 56 const bool logToMetricReportsCollection, 57 const uint64_t interval, 58 ReadingParametersPastVersion metricParams) { 59 constexpr auto enabledDefault = true; 60 constexpr uint64_t appendLimitDefault = 0; 61 constexpr ReportUpdates reportUpdatesDefault = 62 ReportUpdates::overwrite; 63 64 std::vector<ReportAction> reportActions; 65 66 if (emitsReadingsUpdate) 67 { 68 reportActions.emplace_back( 69 ReportAction::emitsReadingsUpdate); 70 } 71 if (logToMetricReportsCollection) 72 { 73 reportActions.emplace_back( 74 ReportAction::logToMetricReportsCollection); 75 } 76 77 return addReport(yield, reportName, 78 utils::toReportingType(reportingType), 79 reportActions, Milliseconds(interval), 80 appendLimitDefault, reportUpdatesDefault, 81 convertToReadingParameters( 82 std::move(metricParams)), 83 enabledDefault) 84 .getPath(); 85 }); 86 87 dbusIface.register_method( 88 "AddReportFutureVersion", 89 [this](boost::asio::yield_context& yield, 90 const std::string& reportName, 91 const std::string& reportingType, 92 const std::string& reportUpdates, 93 const uint64_t appendLimit, 94 const std::vector<std::string>& reportActions, 95 const uint64_t interval, 96 ReadingParameters metricParams) { 97 constexpr auto enabledDefault = true; 98 return addReport(yield, reportName, 99 utils::toReportingType(reportingType), 100 utils::transform( 101 reportActions, 102 [](const auto& reportAction) { 103 return utils::toReportAction( 104 reportAction); 105 }), 106 Milliseconds(interval), appendLimit, 107 utils::toReportUpdates(reportUpdates), 108 std::move(metricParams), enabledDefault) 109 .getPath(); 110 }); 111 }); 112 } 113 114 void ReportManager::removeReport(const interfaces::Report* report) 115 { 116 reports.erase( 117 std::remove_if(reports.begin(), reports.end(), 118 [report](const auto& x) { return report == x.get(); }), 119 reports.end()); 120 } 121 122 void ReportManager::verifyReportNameLength(const std::string& reportName) 123 { 124 if (reportName.length() > maxReportNameLength) 125 { 126 throw sdbusplus::exception::SdBusError( 127 static_cast<int>(std::errc::invalid_argument), 128 "Report name exceeds maximum length"); 129 } 130 } 131 132 void ReportManager::verifyAddReport( 133 const std::string& reportName, const ReportingType reportingType, 134 Milliseconds interval, const ReportUpdates reportUpdates, 135 const std::vector<LabeledMetricParameters>& readingParams) 136 { 137 if (reportingType == ReportingType::onChange) 138 { 139 throw sdbusplus::exception::SdBusError( 140 static_cast<int>(std::errc::invalid_argument), 141 "Invalid reportingType"); 142 } 143 144 if (reports.size() >= maxReports) 145 { 146 throw sdbusplus::exception::SdBusError( 147 static_cast<int>(std::errc::too_many_files_open), 148 "Reached maximal report count"); 149 } 150 151 verifyReportNameLength(reportName); 152 153 for (const auto& report : reports) 154 { 155 if (report->getName() == reportName) 156 { 157 throw sdbusplus::exception::SdBusError( 158 static_cast<int>(std::errc::file_exists), "Duplicate report"); 159 } 160 } 161 162 verifyReportUpdates(reportUpdates); 163 164 if (reportingType == ReportingType::periodic && interval < minInterval) 165 { 166 throw sdbusplus::exception::SdBusError( 167 static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 168 } 169 170 if (readingParams.size() > maxReadingParams) 171 172 { 173 throw sdbusplus::exception::SdBusError( 174 static_cast<int>(std::errc::argument_list_too_long), 175 "Too many reading parameters"); 176 } 177 178 try 179 { 180 namespace ts = utils::tstring; 181 182 for (const LabeledMetricParameters& item : readingParams) 183 { 184 utils::toOperationType( 185 utils::toUnderlying(item.at_label<ts::OperationType>())); 186 } 187 } 188 catch (const std::exception& e) 189 { 190 throw sdbusplus::exception::SdBusError( 191 static_cast<int>(std::errc::invalid_argument), e.what()); 192 } 193 } 194 195 interfaces::Report& ReportManager::addReport( 196 boost::asio::yield_context& yield, const std::string& reportName, 197 const ReportingType reportingType, 198 const std::vector<ReportAction>& reportActions, Milliseconds interval, 199 const uint64_t appendLimit, const ReportUpdates reportUpdates, 200 ReadingParameters metricParams, const bool enabled) 201 { 202 auto labeledMetricParams = 203 reportFactory->convertMetricParams(yield, metricParams); 204 205 return addReport(reportName, reportingType, reportActions, interval, 206 appendLimit, reportUpdates, std::move(labeledMetricParams), 207 enabled); 208 } 209 210 interfaces::Report& ReportManager::addReport( 211 const std::string& reportName, const ReportingType reportingType, 212 const std::vector<ReportAction>& reportActions, Milliseconds interval, 213 const uint64_t appendLimit, const ReportUpdates reportUpdates, 214 std::vector<LabeledMetricParameters> labeledMetricParams, 215 const bool enabled) 216 { 217 verifyAddReport(reportName, reportingType, interval, reportUpdates, 218 labeledMetricParams); 219 220 reports.emplace_back(reportFactory->make( 221 reportName, reportingType, reportActions, interval, appendLimit, 222 reportUpdates, *this, *reportStorage, labeledMetricParams, enabled)); 223 return *reports.back(); 224 } 225 226 void ReportManager::loadFromPersistent() 227 { 228 std::vector<interfaces::JsonStorage::FilePath> paths = 229 reportStorage->list(); 230 231 for (const auto& path : paths) 232 { 233 std::optional<nlohmann::json> data = reportStorage->load(path); 234 try 235 { 236 bool enabled = data->at("Enabled").get<bool>(); 237 size_t version = data->at("Version").get<size_t>(); 238 if (version != Report::reportVersion) 239 { 240 throw std::logic_error("Invalid version"); 241 } 242 std::string& name = data->at("Name").get_ref<std::string&>(); 243 244 uint32_t reportingType = data->at("ReportingType").get<uint32_t>(); 245 std::vector<ReportAction> reportActions = utils::transform( 246 data->at("ReportActions").get<std::vector<uint32_t>>(), 247 [](const auto reportAction) { 248 return utils::toReportAction(reportAction); 249 }); 250 uint64_t interval = data->at("Interval").get<uint64_t>(); 251 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>(); 252 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>(); 253 auto readingParameters = 254 data->at("ReadingParameters") 255 .get<std::vector<LabeledMetricParameters>>(); 256 257 addReport(name, utils::toReportingType(reportingType), 258 reportActions, Milliseconds(interval), appendLimit, 259 utils::toReportUpdates(reportUpdates), 260 std::move(readingParameters), enabled); 261 } 262 catch (const std::exception& e) 263 { 264 phosphor::logging::log<phosphor::logging::level::ERR>( 265 "Failed to load report from storage", 266 phosphor::logging::entry( 267 "FILENAME=%s", 268 static_cast<std::filesystem::path>(path).c_str()), 269 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 270 reportStorage->remove(path); 271 } 272 } 273 } 274 275 void ReportManager::updateReport(const std::string& name) 276 { 277 for (auto& report : reports) 278 { 279 if (report->getName() == name) 280 { 281 report->updateReadings(); 282 return; 283 } 284 } 285 } 286 287 void ReportManager::verifyReportUpdates(const ReportUpdates reportUpdates) 288 { 289 if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(), 290 reportUpdates) == supportedReportUpdates.end()) 291 { 292 throw sdbusplus::exception::SdBusError( 293 static_cast<int>(std::errc::invalid_argument), 294 "Invalid ReportUpdates"); 295 } 296 } 297