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" 6b8cc78ddSKrzysztof Grobelny #include "utils/generate_id.hpp" 7d2238194SKrzysztof Grobelny #include "utils/transform.hpp" 8e2362796SWludzik, Jozef 9e2362796SWludzik, Jozef #include <phosphor-logging/log.hpp> 10cb88cfdfSWludzik, Jozef #include <sdbusplus/exception.hpp> 11cb88cfdfSWludzik, Jozef 12e2362796SWludzik, Jozef #include <stdexcept> 1364b75a5bSKrzysztof Grobelny #include <system_error> 1464b75a5bSKrzysztof Grobelny 15dcc4e193SKrzysztof Grobelny ReadingParameters 16dcc4e193SKrzysztof Grobelny convertToReadingParameters(ReadingParametersPastVersion params) 17dcc4e193SKrzysztof Grobelny { 18dcc4e193SKrzysztof Grobelny return utils::transform(params, [](const auto& param) { 19dcc4e193SKrzysztof Grobelny using namespace std::chrono_literals; 20dcc4e193SKrzysztof Grobelny 21b8cc78ddSKrzysztof Grobelny const auto& [sensorPath, operationType, id, metadata] = param; 22b8cc78ddSKrzysztof Grobelny 23dcc4e193SKrzysztof Grobelny return ReadingParameters::value_type( 24b8cc78ddSKrzysztof Grobelny std::vector< 25b8cc78ddSKrzysztof Grobelny std::tuple<sdbusplus::message::object_path, std::string>>{ 26b8cc78ddSKrzysztof Grobelny {sensorPath, metadata}}, 27b8cc78ddSKrzysztof Grobelny operationType, id, utils::enumToString(CollectionTimeScope::point), 28b8cc78ddSKrzysztof Grobelny 0u); 29dcc4e193SKrzysztof Grobelny }); 30dcc4e193SKrzysztof Grobelny } 31dcc4e193SKrzysztof Grobelny 3264b75a5bSKrzysztof Grobelny ReportManager::ReportManager( 332f9f9b87SWludzik, Jozef std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 34e2362796SWludzik, Jozef std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 35cb88cfdfSWludzik, Jozef const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 362f9f9b87SWludzik, Jozef reportFactory(std::move(reportFactoryIn)), 37e2362796SWludzik, Jozef reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 3864b75a5bSKrzysztof Grobelny { 39cb88cfdfSWludzik, Jozef reports.reserve(maxReports); 406ccfcbf5SKrzysztof Grobelny 41e2362796SWludzik, Jozef loadFromPersistent(); 4264b75a5bSKrzysztof Grobelny 43cb88cfdfSWludzik, Jozef reportManagerIface = objServer->add_unique_interface( 442f9f9b87SWludzik, Jozef reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 45cb88cfdfSWludzik, Jozef dbusIface.register_property_r( 46503c1589SWludzik, Jozef "MaxReports", size_t{}, sdbusplus::vtable::property_::const_, 4764b75a5bSKrzysztof Grobelny [](const auto&) { return maxReports; }); 48cb88cfdfSWludzik, Jozef dbusIface.register_property_r( 49b8cc78ddSKrzysztof Grobelny "MaxReportIdLength", size_t{}, 5032859b63SKarol Niczyj sdbusplus::vtable::property_::const_, 51b8cc78ddSKrzysztof Grobelny [](const auto&) { return maxReportIdLength; }); 5232859b63SKarol Niczyj dbusIface.register_property_r( 5364b75a5bSKrzysztof Grobelny "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_, 5464b75a5bSKrzysztof Grobelny [](const auto&) -> uint64_t { return minInterval.count(); }); 5564b75a5bSKrzysztof Grobelny 56cb88cfdfSWludzik, Jozef dbusIface.register_method( 57e2362796SWludzik, Jozef "AddReport", [this](boost::asio::yield_context& yield, 58b8cc78ddSKrzysztof Grobelny const std::string& reportId, 59cb88cfdfSWludzik, Jozef const std::string& reportingType, 60cb88cfdfSWludzik, Jozef const bool emitsReadingsUpdate, 61cb88cfdfSWludzik, Jozef const bool logToMetricReportsCollection, 62cb88cfdfSWludzik, Jozef const uint64_t interval, 63dcc4e193SKrzysztof Grobelny ReadingParametersPastVersion metricParams) { 647e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 653eb56865SSzymon Dompke constexpr uint64_t appendLimitDefault = 0; 663eb56865SSzymon Dompke constexpr ReportUpdates reportUpdatesDefault = 6751497a0cSKrzysztof Grobelny ReportUpdates::overwrite; 6851497a0cSKrzysztof Grobelny 6951497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions; 7051497a0cSKrzysztof Grobelny 7151497a0cSKrzysztof Grobelny if (emitsReadingsUpdate) 7251497a0cSKrzysztof Grobelny { 7351497a0cSKrzysztof Grobelny reportActions.emplace_back( 7451497a0cSKrzysztof Grobelny ReportAction::emitsReadingsUpdate); 7551497a0cSKrzysztof Grobelny } 7651497a0cSKrzysztof Grobelny if (logToMetricReportsCollection) 7751497a0cSKrzysztof Grobelny { 7851497a0cSKrzysztof Grobelny reportActions.emplace_back( 7951497a0cSKrzysztof Grobelny ReportAction::logToMetricReportsCollection); 8051497a0cSKrzysztof Grobelny } 8151497a0cSKrzysztof Grobelny 82b8cc78ddSKrzysztof Grobelny return addReport(yield, reportId, reportId, 8351497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 8451497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), 8551497a0cSKrzysztof Grobelny appendLimitDefault, reportUpdatesDefault, 86dcc4e193SKrzysztof Grobelny convertToReadingParameters( 877e098e93SLukasz Kazmierczak std::move(metricParams)), 887e098e93SLukasz Kazmierczak enabledDefault) 89dcc4e193SKrzysztof Grobelny .getPath(); 90dcc4e193SKrzysztof Grobelny }); 91dcc4e193SKrzysztof Grobelny 92dcc4e193SKrzysztof Grobelny dbusIface.register_method( 93dcc4e193SKrzysztof Grobelny "AddReportFutureVersion", 94b8cc78ddSKrzysztof Grobelny [this]( 95b8cc78ddSKrzysztof Grobelny boost::asio::yield_context& yield, 96b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 97dcc4e193SKrzysztof Grobelny const std::string& reportingType, 983eb56865SSzymon Dompke const std::string& reportUpdates, 9951497a0cSKrzysztof Grobelny const uint64_t appendLimit, 10051497a0cSKrzysztof Grobelny const std::vector<std::string>& reportActions, 101b8cc78ddSKrzysztof Grobelny const uint64_t interval, ReadingParameters metricParams) { 1027e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 103b8cc78ddSKrzysztof Grobelny return addReport(yield, reportId, reportName, 10451497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 10551497a0cSKrzysztof Grobelny utils::transform( 10651497a0cSKrzysztof Grobelny reportActions, 10751497a0cSKrzysztof Grobelny [](const auto& reportAction) { 10851497a0cSKrzysztof Grobelny return utils::toReportAction( 10951497a0cSKrzysztof Grobelny reportAction); 11051497a0cSKrzysztof Grobelny }), 1113eb56865SSzymon Dompke Milliseconds(interval), appendLimit, 11251497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 11351497a0cSKrzysztof Grobelny std::move(metricParams), enabledDefault) 114d2238194SKrzysztof Grobelny .getPath(); 115e2362796SWludzik, Jozef }); 116e2362796SWludzik, Jozef }); 117e2362796SWludzik, Jozef } 118e2362796SWludzik, Jozef 119e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report) 120e2362796SWludzik, Jozef { 121e2362796SWludzik, Jozef reports.erase( 122e2362796SWludzik, Jozef std::remove_if(reports.begin(), reports.end(), 123e2362796SWludzik, Jozef [report](const auto& x) { return report == x.get(); }), 124e2362796SWludzik, Jozef reports.end()); 125e2362796SWludzik, Jozef } 126e2362796SWludzik, Jozef 127dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport( 128b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 129b8cc78ddSKrzysztof Grobelny const ReportingType reportingType, Milliseconds interval, 130cd5b0b7eSAnkita Vilas Gawade const ReportUpdates reportUpdates, const uint64_t appendLimit, 131dcc4e193SKrzysztof Grobelny const std::vector<LabeledMetricParameters>& readingParams) 132e2362796SWludzik, Jozef { 13351497a0cSKrzysztof Grobelny if (reportingType == ReportingType::onChange) 13451497a0cSKrzysztof Grobelny { 13551497a0cSKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 13651497a0cSKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), 13751497a0cSKrzysztof Grobelny "Invalid reportingType"); 13851497a0cSKrzysztof Grobelny } 13951497a0cSKrzysztof Grobelny 140cb88cfdfSWludzik, Jozef if (reports.size() >= maxReports) 141cb88cfdfSWludzik, Jozef { 142cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 143cb88cfdfSWludzik, Jozef static_cast<int>(std::errc::too_many_files_open), 144cb88cfdfSWludzik, Jozef "Reached maximal report count"); 14564b75a5bSKrzysztof Grobelny } 14664b75a5bSKrzysztof Grobelny 147*e6c417cfSKrzysztof Grobelny if (appendLimit > maxAppendLimit && 148*e6c417cfSKrzysztof Grobelny appendLimit != std::numeric_limits<uint64_t>::max()) 149cd5b0b7eSAnkita Vilas Gawade { 150cd5b0b7eSAnkita Vilas Gawade throw sdbusplus::exception::SdBusError( 151cd5b0b7eSAnkita Vilas Gawade static_cast<int>(std::errc::invalid_argument), 152cd5b0b7eSAnkita Vilas Gawade "Append limit out of range"); 153cd5b0b7eSAnkita Vilas Gawade } 154cd5b0b7eSAnkita Vilas Gawade 15551497a0cSKrzysztof Grobelny if (reportingType == ReportingType::periodic && interval < minInterval) 156cb88cfdfSWludzik, Jozef { 157cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 158e2362796SWludzik, Jozef static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 159cb88cfdfSWludzik, Jozef } 160bc766b4dSWludzik, Jozef 161cd5b0b7eSAnkita Vilas Gawade size_t metricCount = 0; 162cd5b0b7eSAnkita Vilas Gawade for (auto metricParam : readingParams) 163cd5b0b7eSAnkita Vilas Gawade { 164cd5b0b7eSAnkita Vilas Gawade auto metricParamsVec = 165cd5b0b7eSAnkita Vilas Gawade metricParam.at_label<utils::tstring::SensorPath>(); 166cd5b0b7eSAnkita Vilas Gawade metricCount += metricParamsVec.size(); 167cd5b0b7eSAnkita Vilas Gawade } 168e8fc5751SKrzysztof Grobelny 169cd5b0b7eSAnkita Vilas Gawade if (readingParams.size() > maxNumberMetrics || 170cd5b0b7eSAnkita Vilas Gawade metricCount > maxNumberMetrics) 171bc766b4dSWludzik, Jozef { 172bc766b4dSWludzik, Jozef throw sdbusplus::exception::SdBusError( 173bc766b4dSWludzik, Jozef static_cast<int>(std::errc::argument_list_too_long), 174bc766b4dSWludzik, Jozef "Too many reading parameters"); 175bc766b4dSWludzik, Jozef } 176e8fc5751SKrzysztof Grobelny 177e8fc5751SKrzysztof Grobelny try 178e8fc5751SKrzysztof Grobelny { 179dcc4e193SKrzysztof Grobelny namespace ts = utils::tstring; 180dcc4e193SKrzysztof Grobelny 181dcc4e193SKrzysztof Grobelny for (const LabeledMetricParameters& item : readingParams) 182e8fc5751SKrzysztof Grobelny { 183dcc4e193SKrzysztof Grobelny utils::toOperationType( 184dcc4e193SKrzysztof Grobelny utils::toUnderlying(item.at_label<ts::OperationType>())); 185e8fc5751SKrzysztof Grobelny } 186e8fc5751SKrzysztof Grobelny } 187e8fc5751SKrzysztof Grobelny catch (const std::exception& e) 188e8fc5751SKrzysztof Grobelny { 189e8fc5751SKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 190e8fc5751SKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), e.what()); 191e8fc5751SKrzysztof Grobelny } 192d2238194SKrzysztof Grobelny } 193cb88cfdfSWludzik, Jozef 194d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 195b8cc78ddSKrzysztof Grobelny boost::asio::yield_context& yield, const std::string& reportId, 196b8cc78ddSKrzysztof Grobelny const std::string& reportName, const ReportingType reportingType, 19751497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 19851497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 1997e098e93SLukasz Kazmierczak ReadingParameters metricParams, const bool enabled) 200d2238194SKrzysztof Grobelny { 201dcc4e193SKrzysztof Grobelny auto labeledMetricParams = 202dcc4e193SKrzysztof Grobelny reportFactory->convertMetricParams(yield, metricParams); 203d2238194SKrzysztof Grobelny 204b8cc78ddSKrzysztof Grobelny return addReport(reportId, reportName, reportingType, reportActions, 205b8cc78ddSKrzysztof Grobelny interval, appendLimit, reportUpdates, 206b8cc78ddSKrzysztof Grobelny std::move(labeledMetricParams), enabled); 207d2238194SKrzysztof Grobelny } 208d2238194SKrzysztof Grobelny 209d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 210b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 211b8cc78ddSKrzysztof Grobelny const ReportingType reportingType, 21251497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 21351497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 2147e098e93SLukasz Kazmierczak std::vector<LabeledMetricParameters> labeledMetricParams, 2157e098e93SLukasz Kazmierczak const bool enabled) 216d2238194SKrzysztof Grobelny { 217b8cc78ddSKrzysztof Grobelny const auto existingReportIds = utils::transform( 218b8cc78ddSKrzysztof Grobelny reports, [](const auto& report) { return report->getId(); }); 219b8cc78ddSKrzysztof Grobelny 220a950e42bSKrzysztof Grobelny auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault, 221a950e42bSKrzysztof Grobelny existingReportIds, maxReportIdLength); 222b8cc78ddSKrzysztof Grobelny 223b8cc78ddSKrzysztof Grobelny verifyAddReport(id, name, reportingType, interval, reportUpdates, 224cd5b0b7eSAnkita Vilas Gawade appendLimit, labeledMetricParams); 225d2238194SKrzysztof Grobelny 2263eb56865SSzymon Dompke reports.emplace_back(reportFactory->make( 227b8cc78ddSKrzysztof Grobelny id, name, reportingType, reportActions, interval, appendLimit, 22851497a0cSKrzysztof Grobelny reportUpdates, *this, *reportStorage, labeledMetricParams, enabled)); 229d2238194SKrzysztof Grobelny return *reports.back(); 230cb88cfdfSWludzik, Jozef } 231cb88cfdfSWludzik, Jozef 232e2362796SWludzik, Jozef void ReportManager::loadFromPersistent() 233cb88cfdfSWludzik, Jozef { 234e2362796SWludzik, Jozef std::vector<interfaces::JsonStorage::FilePath> paths = 235e2362796SWludzik, Jozef reportStorage->list(); 236e2362796SWludzik, Jozef 237e2362796SWludzik, Jozef for (const auto& path : paths) 238e2362796SWludzik, Jozef { 239e2362796SWludzik, Jozef std::optional<nlohmann::json> data = reportStorage->load(path); 240e2362796SWludzik, Jozef try 241e2362796SWludzik, Jozef { 242e2362796SWludzik, Jozef size_t version = data->at("Version").get<size_t>(); 243e2362796SWludzik, Jozef if (version != Report::reportVersion) 244e2362796SWludzik, Jozef { 245e2362796SWludzik, Jozef throw std::logic_error("Invalid version"); 246e2362796SWludzik, Jozef } 247b8cc78ddSKrzysztof Grobelny bool enabled = data->at("Enabled").get<bool>(); 248b8cc78ddSKrzysztof Grobelny std::string& id = data->at("Id").get_ref<std::string&>(); 249e2362796SWludzik, Jozef std::string& name = data->at("Name").get_ref<std::string&>(); 25051497a0cSKrzysztof Grobelny 25151497a0cSKrzysztof Grobelny uint32_t reportingType = data->at("ReportingType").get<uint32_t>(); 25251497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions = utils::transform( 25351497a0cSKrzysztof Grobelny data->at("ReportActions").get<std::vector<uint32_t>>(), 25451497a0cSKrzysztof Grobelny [](const auto reportAction) { 25551497a0cSKrzysztof Grobelny return utils::toReportAction(reportAction); 25651497a0cSKrzysztof Grobelny }); 257e2362796SWludzik, Jozef uint64_t interval = data->at("Interval").get<uint64_t>(); 2583eb56865SSzymon Dompke uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>(); 25951497a0cSKrzysztof Grobelny uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>(); 260d2238194SKrzysztof Grobelny auto readingParameters = 261d2238194SKrzysztof Grobelny data->at("ReadingParameters") 262d2238194SKrzysztof Grobelny .get<std::vector<LabeledMetricParameters>>(); 263e2362796SWludzik, Jozef 264b8cc78ddSKrzysztof Grobelny addReport(id, name, utils::toReportingType(reportingType), 26551497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), appendLimit, 26651497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 26751497a0cSKrzysztof Grobelny std::move(readingParameters), enabled); 268e2362796SWludzik, Jozef } 269e2362796SWludzik, Jozef catch (const std::exception& e) 270e2362796SWludzik, Jozef { 271e2362796SWludzik, Jozef phosphor::logging::log<phosphor::logging::level::ERR>( 272e2362796SWludzik, Jozef "Failed to load report from storage", 273e2362796SWludzik, Jozef phosphor::logging::entry( 274982c5b5bSWludzik, Jozef "FILENAME=%s", 275e2362796SWludzik, Jozef static_cast<std::filesystem::path>(path).c_str()), 276982c5b5bSWludzik, Jozef phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 277e2362796SWludzik, Jozef reportStorage->remove(path); 278e2362796SWludzik, Jozef } 279e2362796SWludzik, Jozef } 28064b75a5bSKrzysztof Grobelny } 281d960e1f3SWludzik, Jozef 282b8cc78ddSKrzysztof Grobelny void ReportManager::updateReport(const std::string& id) 283d960e1f3SWludzik, Jozef { 284d960e1f3SWludzik, Jozef for (auto& report : reports) 285d960e1f3SWludzik, Jozef { 286b8cc78ddSKrzysztof Grobelny if (report->getId() == id) 287d960e1f3SWludzik, Jozef { 288d960e1f3SWludzik, Jozef report->updateReadings(); 289d960e1f3SWludzik, Jozef return; 290d960e1f3SWludzik, Jozef } 291d960e1f3SWludzik, Jozef } 292d960e1f3SWludzik, Jozef } 293