164b75a5bSKrzysztof Grobelny #include "report_manager.hpp" 264b75a5bSKrzysztof Grobelny 3e2362796SWludzik, Jozef #include "report.hpp" 4dcc4e193SKrzysztof Grobelny #include "types/report_types.hpp" 5e8fc5751SKrzysztof Grobelny #include "utils/conversion.hpp" 6d2238194SKrzysztof Grobelny #include "utils/transform.hpp" 7e2362796SWludzik, Jozef 8e2362796SWludzik, Jozef #include <phosphor-logging/log.hpp> 9cb88cfdfSWludzik, Jozef #include <sdbusplus/exception.hpp> 10cb88cfdfSWludzik, Jozef 11e2362796SWludzik, Jozef #include <stdexcept> 1264b75a5bSKrzysztof Grobelny #include <system_error> 1364b75a5bSKrzysztof Grobelny 14dcc4e193SKrzysztof Grobelny ReadingParameters 15dcc4e193SKrzysztof Grobelny convertToReadingParameters(ReadingParametersPastVersion params) 16dcc4e193SKrzysztof Grobelny { 17dcc4e193SKrzysztof Grobelny return utils::transform(params, [](const auto& param) { 18dcc4e193SKrzysztof Grobelny using namespace std::chrono_literals; 19dcc4e193SKrzysztof Grobelny 20dcc4e193SKrzysztof Grobelny return ReadingParameters::value_type( 21dcc4e193SKrzysztof Grobelny std::vector{{std::get<0>(param)}}, std::get<1>(param), 22dcc4e193SKrzysztof Grobelny std::get<2>(param), std::get<3>(param), 23dcc4e193SKrzysztof Grobelny utils::enumToString(CollectionTimeScope::point), 0u); 24dcc4e193SKrzysztof Grobelny }); 25dcc4e193SKrzysztof Grobelny } 26dcc4e193SKrzysztof Grobelny 2764b75a5bSKrzysztof Grobelny ReportManager::ReportManager( 282f9f9b87SWludzik, Jozef std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 29e2362796SWludzik, Jozef std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 30cb88cfdfSWludzik, Jozef const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 312f9f9b87SWludzik, Jozef reportFactory(std::move(reportFactoryIn)), 32e2362796SWludzik, Jozef reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 3364b75a5bSKrzysztof Grobelny { 34cb88cfdfSWludzik, Jozef reports.reserve(maxReports); 356ccfcbf5SKrzysztof Grobelny 36e2362796SWludzik, Jozef loadFromPersistent(); 3764b75a5bSKrzysztof Grobelny 38cb88cfdfSWludzik, Jozef reportManagerIface = objServer->add_unique_interface( 392f9f9b87SWludzik, Jozef reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 40cb88cfdfSWludzik, Jozef dbusIface.register_property_r( 41503c1589SWludzik, Jozef "MaxReports", size_t{}, sdbusplus::vtable::property_::const_, 4264b75a5bSKrzysztof Grobelny [](const auto&) { return maxReports; }); 43cb88cfdfSWludzik, Jozef dbusIface.register_property_r( 4432859b63SKarol Niczyj "MaxReportNameLength", size_t{}, 4532859b63SKarol Niczyj sdbusplus::vtable::property_::const_, 4632859b63SKarol Niczyj [](const auto&) { return maxReportNameLength; }); 4732859b63SKarol Niczyj dbusIface.register_property_r( 4864b75a5bSKrzysztof Grobelny "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_, 4964b75a5bSKrzysztof Grobelny [](const auto&) -> uint64_t { return minInterval.count(); }); 5064b75a5bSKrzysztof Grobelny 51cb88cfdfSWludzik, Jozef dbusIface.register_method( 52e2362796SWludzik, Jozef "AddReport", [this](boost::asio::yield_context& yield, 53e2362796SWludzik, Jozef const std::string& reportName, 54cb88cfdfSWludzik, Jozef const std::string& reportingType, 55cb88cfdfSWludzik, Jozef const bool emitsReadingsUpdate, 56cb88cfdfSWludzik, Jozef const bool logToMetricReportsCollection, 57cb88cfdfSWludzik, Jozef const uint64_t interval, 58dcc4e193SKrzysztof Grobelny ReadingParametersPastVersion metricParams) { 597e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 603eb56865SSzymon Dompke constexpr uint64_t appendLimitDefault = 0; 613eb56865SSzymon Dompke constexpr ReportUpdates reportUpdatesDefault = 62*51497a0cSKrzysztof Grobelny ReportUpdates::overwrite; 63*51497a0cSKrzysztof Grobelny 64*51497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions; 65*51497a0cSKrzysztof Grobelny 66*51497a0cSKrzysztof Grobelny if (emitsReadingsUpdate) 67*51497a0cSKrzysztof Grobelny { 68*51497a0cSKrzysztof Grobelny reportActions.emplace_back( 69*51497a0cSKrzysztof Grobelny ReportAction::emitsReadingsUpdate); 70*51497a0cSKrzysztof Grobelny } 71*51497a0cSKrzysztof Grobelny if (logToMetricReportsCollection) 72*51497a0cSKrzysztof Grobelny { 73*51497a0cSKrzysztof Grobelny reportActions.emplace_back( 74*51497a0cSKrzysztof Grobelny ReportAction::logToMetricReportsCollection); 75*51497a0cSKrzysztof Grobelny } 76*51497a0cSKrzysztof Grobelny 77*51497a0cSKrzysztof Grobelny return addReport(yield, reportName, 78*51497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 79*51497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), 80*51497a0cSKrzysztof Grobelny appendLimitDefault, reportUpdatesDefault, 81dcc4e193SKrzysztof Grobelny convertToReadingParameters( 827e098e93SLukasz Kazmierczak std::move(metricParams)), 837e098e93SLukasz Kazmierczak enabledDefault) 84dcc4e193SKrzysztof Grobelny .getPath(); 85dcc4e193SKrzysztof Grobelny }); 86dcc4e193SKrzysztof Grobelny 87dcc4e193SKrzysztof Grobelny dbusIface.register_method( 88dcc4e193SKrzysztof Grobelny "AddReportFutureVersion", 89*51497a0cSKrzysztof Grobelny [this](boost::asio::yield_context& yield, 90dcc4e193SKrzysztof Grobelny const std::string& reportName, 91dcc4e193SKrzysztof Grobelny const std::string& reportingType, 923eb56865SSzymon Dompke const std::string& reportUpdates, 93*51497a0cSKrzysztof Grobelny const uint64_t appendLimit, 94*51497a0cSKrzysztof Grobelny const std::vector<std::string>& reportActions, 95*51497a0cSKrzysztof Grobelny const uint64_t interval, 96*51497a0cSKrzysztof Grobelny ReadingParameters metricParams) { 977e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 98*51497a0cSKrzysztof Grobelny return addReport(yield, reportName, 99*51497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 100*51497a0cSKrzysztof Grobelny utils::transform( 101*51497a0cSKrzysztof Grobelny reportActions, 102*51497a0cSKrzysztof Grobelny [](const auto& reportAction) { 103*51497a0cSKrzysztof Grobelny return utils::toReportAction( 104*51497a0cSKrzysztof Grobelny reportAction); 105*51497a0cSKrzysztof Grobelny }), 1063eb56865SSzymon Dompke Milliseconds(interval), appendLimit, 107*51497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 108*51497a0cSKrzysztof Grobelny std::move(metricParams), enabledDefault) 109d2238194SKrzysztof Grobelny .getPath(); 110e2362796SWludzik, Jozef }); 111e2362796SWludzik, Jozef }); 112e2362796SWludzik, Jozef } 113e2362796SWludzik, Jozef 114e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report) 115e2362796SWludzik, Jozef { 116e2362796SWludzik, Jozef reports.erase( 117e2362796SWludzik, Jozef std::remove_if(reports.begin(), reports.end(), 118e2362796SWludzik, Jozef [report](const auto& x) { return report == x.get(); }), 119e2362796SWludzik, Jozef reports.end()); 120e2362796SWludzik, Jozef } 121e2362796SWludzik, Jozef 12232859b63SKarol Niczyj void ReportManager::verifyReportNameLength(const std::string& reportName) 12332859b63SKarol Niczyj { 12432859b63SKarol Niczyj if (reportName.length() > maxReportNameLength) 12532859b63SKarol Niczyj { 12632859b63SKarol Niczyj throw sdbusplus::exception::SdBusError( 12732859b63SKarol Niczyj static_cast<int>(std::errc::invalid_argument), 128e28aa53dSSzymon Dompke "Report name exceeds maximum length"); 12932859b63SKarol Niczyj } 13032859b63SKarol Niczyj } 13132859b63SKarol Niczyj 132dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport( 133*51497a0cSKrzysztof Grobelny const std::string& reportName, const ReportingType reportingType, 134*51497a0cSKrzysztof Grobelny Milliseconds interval, const ReportUpdates reportUpdates, 135dcc4e193SKrzysztof Grobelny const std::vector<LabeledMetricParameters>& readingParams) 136e2362796SWludzik, Jozef { 137*51497a0cSKrzysztof Grobelny if (reportingType == ReportingType::onChange) 138*51497a0cSKrzysztof Grobelny { 139*51497a0cSKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 140*51497a0cSKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), 141*51497a0cSKrzysztof Grobelny "Invalid reportingType"); 142*51497a0cSKrzysztof Grobelny } 143*51497a0cSKrzysztof Grobelny 144cb88cfdfSWludzik, Jozef if (reports.size() >= maxReports) 145cb88cfdfSWludzik, Jozef { 146cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 147cb88cfdfSWludzik, Jozef static_cast<int>(std::errc::too_many_files_open), 148cb88cfdfSWludzik, Jozef "Reached maximal report count"); 14964b75a5bSKrzysztof Grobelny } 15064b75a5bSKrzysztof Grobelny 15132859b63SKarol Niczyj verifyReportNameLength(reportName); 15232859b63SKarol Niczyj 153cb88cfdfSWludzik, Jozef for (const auto& report : reports) 15464b75a5bSKrzysztof Grobelny { 1552f9f9b87SWludzik, Jozef if (report->getName() == reportName) 156cb88cfdfSWludzik, Jozef { 157cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 158e2362796SWludzik, Jozef static_cast<int>(std::errc::file_exists), "Duplicate report"); 159cb88cfdfSWludzik, Jozef } 160cb88cfdfSWludzik, Jozef } 161cb88cfdfSWludzik, Jozef 1623eb56865SSzymon Dompke verifyReportUpdates(reportUpdates); 1633eb56865SSzymon Dompke 164*51497a0cSKrzysztof Grobelny if (reportingType == ReportingType::periodic && interval < minInterval) 165cb88cfdfSWludzik, Jozef { 166cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 167e2362796SWludzik, Jozef static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 168cb88cfdfSWludzik, Jozef } 169bc766b4dSWludzik, Jozef 170503c1589SWludzik, Jozef if (readingParams.size() > maxReadingParams) 171e8fc5751SKrzysztof Grobelny 172bc766b4dSWludzik, Jozef { 173bc766b4dSWludzik, Jozef throw sdbusplus::exception::SdBusError( 174bc766b4dSWludzik, Jozef static_cast<int>(std::errc::argument_list_too_long), 175bc766b4dSWludzik, Jozef "Too many reading parameters"); 176bc766b4dSWludzik, Jozef } 177e8fc5751SKrzysztof Grobelny 178e8fc5751SKrzysztof Grobelny try 179e8fc5751SKrzysztof Grobelny { 180dcc4e193SKrzysztof Grobelny namespace ts = utils::tstring; 181dcc4e193SKrzysztof Grobelny 182dcc4e193SKrzysztof Grobelny for (const LabeledMetricParameters& item : readingParams) 183e8fc5751SKrzysztof Grobelny { 184dcc4e193SKrzysztof Grobelny utils::toOperationType( 185dcc4e193SKrzysztof Grobelny utils::toUnderlying(item.at_label<ts::OperationType>())); 186e8fc5751SKrzysztof Grobelny } 187e8fc5751SKrzysztof Grobelny } 188e8fc5751SKrzysztof Grobelny catch (const std::exception& e) 189e8fc5751SKrzysztof Grobelny { 190e8fc5751SKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 191e8fc5751SKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), e.what()); 192e8fc5751SKrzysztof Grobelny } 193d2238194SKrzysztof Grobelny } 194cb88cfdfSWludzik, Jozef 195d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 196d2238194SKrzysztof Grobelny boost::asio::yield_context& yield, const std::string& reportName, 197*51497a0cSKrzysztof Grobelny const ReportingType reportingType, 198*51497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 199*51497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 2007e098e93SLukasz Kazmierczak ReadingParameters metricParams, const bool enabled) 201d2238194SKrzysztof Grobelny { 202dcc4e193SKrzysztof Grobelny auto labeledMetricParams = 203dcc4e193SKrzysztof Grobelny reportFactory->convertMetricParams(yield, metricParams); 204d2238194SKrzysztof Grobelny 205*51497a0cSKrzysztof Grobelny return addReport(reportName, reportingType, reportActions, interval, 206*51497a0cSKrzysztof Grobelny appendLimit, reportUpdates, std::move(labeledMetricParams), 207*51497a0cSKrzysztof Grobelny enabled); 208d2238194SKrzysztof Grobelny } 209d2238194SKrzysztof Grobelny 210d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 211*51497a0cSKrzysztof Grobelny const std::string& reportName, const ReportingType reportingType, 212*51497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 213*51497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 2147e098e93SLukasz Kazmierczak std::vector<LabeledMetricParameters> labeledMetricParams, 2157e098e93SLukasz Kazmierczak const bool enabled) 216d2238194SKrzysztof Grobelny { 2173eb56865SSzymon Dompke verifyAddReport(reportName, reportingType, interval, reportUpdates, 2183eb56865SSzymon Dompke labeledMetricParams); 219d2238194SKrzysztof Grobelny 2203eb56865SSzymon Dompke reports.emplace_back(reportFactory->make( 221*51497a0cSKrzysztof Grobelny reportName, reportingType, reportActions, interval, appendLimit, 222*51497a0cSKrzysztof Grobelny reportUpdates, *this, *reportStorage, labeledMetricParams, enabled)); 223d2238194SKrzysztof Grobelny return *reports.back(); 224cb88cfdfSWludzik, Jozef } 225cb88cfdfSWludzik, Jozef 226e2362796SWludzik, Jozef void ReportManager::loadFromPersistent() 227cb88cfdfSWludzik, Jozef { 228e2362796SWludzik, Jozef std::vector<interfaces::JsonStorage::FilePath> paths = 229e2362796SWludzik, Jozef reportStorage->list(); 230e2362796SWludzik, Jozef 231e2362796SWludzik, Jozef for (const auto& path : paths) 232e2362796SWludzik, Jozef { 233e2362796SWludzik, Jozef std::optional<nlohmann::json> data = reportStorage->load(path); 234e2362796SWludzik, Jozef try 235e2362796SWludzik, Jozef { 2367e098e93SLukasz Kazmierczak bool enabled = data->at("Enabled").get<bool>(); 237e2362796SWludzik, Jozef size_t version = data->at("Version").get<size_t>(); 238e2362796SWludzik, Jozef if (version != Report::reportVersion) 239e2362796SWludzik, Jozef { 240e2362796SWludzik, Jozef throw std::logic_error("Invalid version"); 241e2362796SWludzik, Jozef } 242e2362796SWludzik, Jozef std::string& name = data->at("Name").get_ref<std::string&>(); 243*51497a0cSKrzysztof Grobelny 244*51497a0cSKrzysztof Grobelny uint32_t reportingType = data->at("ReportingType").get<uint32_t>(); 245*51497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions = utils::transform( 246*51497a0cSKrzysztof Grobelny data->at("ReportActions").get<std::vector<uint32_t>>(), 247*51497a0cSKrzysztof Grobelny [](const auto reportAction) { 248*51497a0cSKrzysztof Grobelny return utils::toReportAction(reportAction); 249*51497a0cSKrzysztof Grobelny }); 250e2362796SWludzik, Jozef uint64_t interval = data->at("Interval").get<uint64_t>(); 2513eb56865SSzymon Dompke uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>(); 252*51497a0cSKrzysztof Grobelny uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>(); 253d2238194SKrzysztof Grobelny auto readingParameters = 254d2238194SKrzysztof Grobelny data->at("ReadingParameters") 255d2238194SKrzysztof Grobelny .get<std::vector<LabeledMetricParameters>>(); 256e2362796SWludzik, Jozef 257*51497a0cSKrzysztof Grobelny addReport(name, utils::toReportingType(reportingType), 258*51497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), appendLimit, 259*51497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 260*51497a0cSKrzysztof Grobelny std::move(readingParameters), enabled); 261e2362796SWludzik, Jozef } 262e2362796SWludzik, Jozef catch (const std::exception& e) 263e2362796SWludzik, Jozef { 264e2362796SWludzik, Jozef phosphor::logging::log<phosphor::logging::level::ERR>( 265e2362796SWludzik, Jozef "Failed to load report from storage", 266e2362796SWludzik, Jozef phosphor::logging::entry( 267982c5b5bSWludzik, Jozef "FILENAME=%s", 268e2362796SWludzik, Jozef static_cast<std::filesystem::path>(path).c_str()), 269982c5b5bSWludzik, Jozef phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 270e2362796SWludzik, Jozef reportStorage->remove(path); 271e2362796SWludzik, Jozef } 272e2362796SWludzik, Jozef } 27364b75a5bSKrzysztof Grobelny } 274d960e1f3SWludzik, Jozef 275d960e1f3SWludzik, Jozef void ReportManager::updateReport(const std::string& name) 276d960e1f3SWludzik, Jozef { 277d960e1f3SWludzik, Jozef for (auto& report : reports) 278d960e1f3SWludzik, Jozef { 279d960e1f3SWludzik, Jozef if (report->getName() == name) 280d960e1f3SWludzik, Jozef { 281d960e1f3SWludzik, Jozef report->updateReadings(); 282d960e1f3SWludzik, Jozef return; 283d960e1f3SWludzik, Jozef } 284d960e1f3SWludzik, Jozef } 285d960e1f3SWludzik, Jozef } 2863eb56865SSzymon Dompke 287*51497a0cSKrzysztof Grobelny void ReportManager::verifyReportUpdates(const ReportUpdates reportUpdates) 2883eb56865SSzymon Dompke { 2893eb56865SSzymon Dompke if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(), 2903eb56865SSzymon Dompke reportUpdates) == supportedReportUpdates.end()) 2913eb56865SSzymon Dompke { 2923eb56865SSzymon Dompke throw sdbusplus::exception::SdBusError( 2933eb56865SSzymon Dompke static_cast<int>(std::errc::invalid_argument), 2943eb56865SSzymon Dompke "Invalid ReportUpdates"); 2953eb56865SSzymon Dompke } 2963eb56865SSzymon Dompke } 297