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; 60dcc4e193SKrzysztof Grobelny return addReport(yield, reportName, reportingType, 61dcc4e193SKrzysztof Grobelny emitsReadingsUpdate, 62dcc4e193SKrzysztof Grobelny logToMetricReportsCollection, 63dcc4e193SKrzysztof Grobelny Milliseconds(interval), 64dcc4e193SKrzysztof Grobelny convertToReadingParameters( 657e098e93SLukasz Kazmierczak std::move(metricParams)), 667e098e93SLukasz Kazmierczak enabledDefault) 67dcc4e193SKrzysztof Grobelny .getPath(); 68dcc4e193SKrzysztof Grobelny }); 69dcc4e193SKrzysztof Grobelny 70dcc4e193SKrzysztof Grobelny dbusIface.register_method( 71dcc4e193SKrzysztof Grobelny "AddReportFutureVersion", 72dcc4e193SKrzysztof Grobelny [this](boost::asio::yield_context& yield, 73dcc4e193SKrzysztof Grobelny const std::string& reportName, 74dcc4e193SKrzysztof Grobelny const std::string& reportingType, 75dcc4e193SKrzysztof Grobelny const bool emitsReadingsUpdate, 76dcc4e193SKrzysztof Grobelny const bool logToMetricReportsCollection, 77dcc4e193SKrzysztof Grobelny const uint64_t interval, 78d2238194SKrzysztof Grobelny ReadingParameters metricParams) { 797e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 80e2362796SWludzik, Jozef return addReport(yield, reportName, reportingType, 81e2362796SWludzik, Jozef emitsReadingsUpdate, 82e2362796SWludzik, Jozef logToMetricReportsCollection, 83dcc4e193SKrzysztof Grobelny Milliseconds(interval), 847e098e93SLukasz Kazmierczak std::move(metricParams), enabledDefault) 85d2238194SKrzysztof Grobelny .getPath(); 86e2362796SWludzik, Jozef }); 87e2362796SWludzik, Jozef }); 88e2362796SWludzik, Jozef } 89e2362796SWludzik, Jozef 90e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report) 91e2362796SWludzik, Jozef { 92e2362796SWludzik, Jozef reports.erase( 93e2362796SWludzik, Jozef std::remove_if(reports.begin(), reports.end(), 94e2362796SWludzik, Jozef [report](const auto& x) { return report == x.get(); }), 95e2362796SWludzik, Jozef reports.end()); 96e2362796SWludzik, Jozef } 97e2362796SWludzik, Jozef 9832859b63SKarol Niczyj void ReportManager::verifyReportNameLength(const std::string& reportName) 9932859b63SKarol Niczyj { 10032859b63SKarol Niczyj if (reportName.length() > maxReportNameLength) 10132859b63SKarol Niczyj { 10232859b63SKarol Niczyj throw sdbusplus::exception::SdBusError( 10332859b63SKarol Niczyj static_cast<int>(std::errc::invalid_argument), 104*e28aa53dSSzymon Dompke "Report name exceeds maximum length"); 10532859b63SKarol Niczyj } 10632859b63SKarol Niczyj } 10732859b63SKarol Niczyj 108dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport( 109dcc4e193SKrzysztof Grobelny const std::string& reportName, const std::string& reportingType, 110dcc4e193SKrzysztof Grobelny Milliseconds interval, 111dcc4e193SKrzysztof Grobelny const std::vector<LabeledMetricParameters>& readingParams) 112e2362796SWludzik, Jozef { 113cb88cfdfSWludzik, Jozef if (reports.size() >= maxReports) 114cb88cfdfSWludzik, Jozef { 115cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 116cb88cfdfSWludzik, Jozef static_cast<int>(std::errc::too_many_files_open), 117cb88cfdfSWludzik, Jozef "Reached maximal report count"); 11864b75a5bSKrzysztof Grobelny } 11964b75a5bSKrzysztof Grobelny 12032859b63SKarol Niczyj verifyReportNameLength(reportName); 12132859b63SKarol Niczyj 122cb88cfdfSWludzik, Jozef for (const auto& report : reports) 12364b75a5bSKrzysztof Grobelny { 1242f9f9b87SWludzik, Jozef if (report->getName() == reportName) 125cb88cfdfSWludzik, Jozef { 126cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 127e2362796SWludzik, Jozef static_cast<int>(std::errc::file_exists), "Duplicate report"); 128cb88cfdfSWludzik, Jozef } 129cb88cfdfSWludzik, Jozef } 130cb88cfdfSWludzik, Jozef 131bc766b4dSWludzik, Jozef auto found = std::find(supportedReportingType.begin(), 132bc766b4dSWludzik, Jozef supportedReportingType.end(), reportingType); 133bc766b4dSWludzik, Jozef if (found == supportedReportingType.end()) 134bc766b4dSWludzik, Jozef { 135bc766b4dSWludzik, Jozef throw sdbusplus::exception::SdBusError( 136bc766b4dSWludzik, Jozef static_cast<int>(std::errc::invalid_argument), 137bc766b4dSWludzik, Jozef "Invalid reportingType"); 138bc766b4dSWludzik, Jozef } 139bc766b4dSWludzik, Jozef 140bc766b4dSWludzik, Jozef if (reportingType == "Periodic" && interval < minInterval) 141cb88cfdfSWludzik, Jozef { 142cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 143e2362796SWludzik, Jozef static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 144cb88cfdfSWludzik, Jozef } 145bc766b4dSWludzik, Jozef 146503c1589SWludzik, Jozef if (readingParams.size() > maxReadingParams) 147e8fc5751SKrzysztof Grobelny 148bc766b4dSWludzik, Jozef { 149bc766b4dSWludzik, Jozef throw sdbusplus::exception::SdBusError( 150bc766b4dSWludzik, Jozef static_cast<int>(std::errc::argument_list_too_long), 151bc766b4dSWludzik, Jozef "Too many reading parameters"); 152bc766b4dSWludzik, Jozef } 153e8fc5751SKrzysztof Grobelny 154e8fc5751SKrzysztof Grobelny try 155e8fc5751SKrzysztof Grobelny { 156dcc4e193SKrzysztof Grobelny namespace ts = utils::tstring; 157dcc4e193SKrzysztof Grobelny 158dcc4e193SKrzysztof Grobelny for (const LabeledMetricParameters& item : readingParams) 159e8fc5751SKrzysztof Grobelny { 160dcc4e193SKrzysztof Grobelny utils::toOperationType( 161dcc4e193SKrzysztof Grobelny utils::toUnderlying(item.at_label<ts::OperationType>())); 162e8fc5751SKrzysztof Grobelny } 163e8fc5751SKrzysztof Grobelny } 164e8fc5751SKrzysztof Grobelny catch (const std::exception& e) 165e8fc5751SKrzysztof Grobelny { 166e8fc5751SKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 167e8fc5751SKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), e.what()); 168e8fc5751SKrzysztof Grobelny } 169d2238194SKrzysztof Grobelny } 170cb88cfdfSWludzik, Jozef 171d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 172d2238194SKrzysztof Grobelny boost::asio::yield_context& yield, const std::string& reportName, 173d2238194SKrzysztof Grobelny const std::string& reportingType, const bool emitsReadingsUpdate, 174dcc4e193SKrzysztof Grobelny const bool logToMetricReportsCollection, Milliseconds interval, 1757e098e93SLukasz Kazmierczak ReadingParameters metricParams, const bool enabled) 176d2238194SKrzysztof Grobelny { 177dcc4e193SKrzysztof Grobelny auto labeledMetricParams = 178dcc4e193SKrzysztof Grobelny reportFactory->convertMetricParams(yield, metricParams); 179d2238194SKrzysztof Grobelny 180dcc4e193SKrzysztof Grobelny return addReport(reportName, reportingType, emitsReadingsUpdate, 181dcc4e193SKrzysztof Grobelny logToMetricReportsCollection, interval, 1827e098e93SLukasz Kazmierczak std::move(labeledMetricParams), enabled); 183d2238194SKrzysztof Grobelny } 184d2238194SKrzysztof Grobelny 185d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 186d2238194SKrzysztof Grobelny const std::string& reportName, const std::string& reportingType, 187d2238194SKrzysztof Grobelny const bool emitsReadingsUpdate, const bool logToMetricReportsCollection, 188dcc4e193SKrzysztof Grobelny Milliseconds interval, 1897e098e93SLukasz Kazmierczak std::vector<LabeledMetricParameters> labeledMetricParams, 1907e098e93SLukasz Kazmierczak const bool enabled) 191d2238194SKrzysztof Grobelny { 192dcc4e193SKrzysztof Grobelny verifyAddReport(reportName, reportingType, interval, labeledMetricParams); 193d2238194SKrzysztof Grobelny 194dcc4e193SKrzysztof Grobelny reports.emplace_back( 195dcc4e193SKrzysztof Grobelny reportFactory->make(reportName, reportingType, emitsReadingsUpdate, 196dcc4e193SKrzysztof Grobelny logToMetricReportsCollection, interval, *this, 1977e098e93SLukasz Kazmierczak *reportStorage, labeledMetricParams, enabled)); 198d2238194SKrzysztof Grobelny return *reports.back(); 199cb88cfdfSWludzik, Jozef } 200cb88cfdfSWludzik, Jozef 201e2362796SWludzik, Jozef void ReportManager::loadFromPersistent() 202cb88cfdfSWludzik, Jozef { 203e2362796SWludzik, Jozef std::vector<interfaces::JsonStorage::FilePath> paths = 204e2362796SWludzik, Jozef reportStorage->list(); 205e2362796SWludzik, Jozef 206e2362796SWludzik, Jozef for (const auto& path : paths) 207e2362796SWludzik, Jozef { 208e2362796SWludzik, Jozef std::optional<nlohmann::json> data = reportStorage->load(path); 209e2362796SWludzik, Jozef try 210e2362796SWludzik, Jozef { 2117e098e93SLukasz Kazmierczak bool enabled = data->at("Enabled").get<bool>(); 212e2362796SWludzik, Jozef size_t version = data->at("Version").get<size_t>(); 213e2362796SWludzik, Jozef if (version != Report::reportVersion) 214e2362796SWludzik, Jozef { 215e2362796SWludzik, Jozef throw std::logic_error("Invalid version"); 216e2362796SWludzik, Jozef } 217e2362796SWludzik, Jozef std::string& name = data->at("Name").get_ref<std::string&>(); 218e2362796SWludzik, Jozef std::string& reportingType = 219e2362796SWludzik, Jozef data->at("ReportingType").get_ref<std::string&>(); 220e2362796SWludzik, Jozef bool emitsReadingsSignal = 221e2362796SWludzik, Jozef data->at("EmitsReadingsUpdate").get<bool>(); 222e2362796SWludzik, Jozef bool logToMetricReportsCollection = 223e2362796SWludzik, Jozef data->at("LogToMetricReportsCollection").get<bool>(); 224e2362796SWludzik, Jozef uint64_t interval = data->at("Interval").get<uint64_t>(); 225d2238194SKrzysztof Grobelny auto readingParameters = 226d2238194SKrzysztof Grobelny data->at("ReadingParameters") 227d2238194SKrzysztof Grobelny .get<std::vector<LabeledMetricParameters>>(); 228e2362796SWludzik, Jozef 229d2238194SKrzysztof Grobelny addReport(name, reportingType, emitsReadingsSignal, 230dcc4e193SKrzysztof Grobelny logToMetricReportsCollection, Milliseconds(interval), 2317e098e93SLukasz Kazmierczak std::move(readingParameters), enabled); 232e2362796SWludzik, Jozef } 233e2362796SWludzik, Jozef catch (const std::exception& e) 234e2362796SWludzik, Jozef { 235e2362796SWludzik, Jozef phosphor::logging::log<phosphor::logging::level::ERR>( 236e2362796SWludzik, Jozef "Failed to load report from storage", 237e2362796SWludzik, Jozef phosphor::logging::entry( 238982c5b5bSWludzik, Jozef "FILENAME=%s", 239e2362796SWludzik, Jozef static_cast<std::filesystem::path>(path).c_str()), 240982c5b5bSWludzik, Jozef phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 241e2362796SWludzik, Jozef reportStorage->remove(path); 242e2362796SWludzik, Jozef } 243e2362796SWludzik, Jozef } 24464b75a5bSKrzysztof Grobelny } 245d960e1f3SWludzik, Jozef 246d960e1f3SWludzik, Jozef void ReportManager::updateReport(const std::string& name) 247d960e1f3SWludzik, Jozef { 248d960e1f3SWludzik, Jozef for (auto& report : reports) 249d960e1f3SWludzik, Jozef { 250d960e1f3SWludzik, Jozef if (report->getName() == name) 251d960e1f3SWludzik, Jozef { 252d960e1f3SWludzik, Jozef report->updateReadings(); 253d960e1f3SWludzik, Jozef return; 254d960e1f3SWludzik, Jozef } 255d960e1f3SWludzik, Jozef } 256d960e1f3SWludzik, Jozef } 257