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, 35e6d48874SKrzysztof Grobelny const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 362f9f9b87SWludzik, Jozef reportFactory(std::move(reportFactoryIn)), 37e6d48874SKrzysztof Grobelny 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(); }); 5560fee077SKrzysztof Grobelny dbusIface.register_property_r( 5660fee077SKrzysztof Grobelny "SupportedOperationTypes", std::vector<std::string>{}, 5760fee077SKrzysztof Grobelny sdbusplus::vtable::property_::const_, 5860fee077SKrzysztof Grobelny [](const auto&) -> std::vector<std::string> { 59fdb06a14SSzymon Dompke return utils::transform<std::vector>( 6060fee077SKrzysztof Grobelny utils::convDataOperationType, [](const auto& item) { 6160fee077SKrzysztof Grobelny return std::string(item.first); 6260fee077SKrzysztof Grobelny }); 6360fee077SKrzysztof Grobelny }); 6464b75a5bSKrzysztof Grobelny 65cb88cfdfSWludzik, Jozef dbusIface.register_method( 66e2362796SWludzik, Jozef "AddReport", [this](boost::asio::yield_context& yield, 67b8cc78ddSKrzysztof Grobelny const std::string& reportId, 68cb88cfdfSWludzik, Jozef const std::string& reportingType, 69cb88cfdfSWludzik, Jozef const bool emitsReadingsUpdate, 70cb88cfdfSWludzik, Jozef const bool logToMetricReportsCollection, 71cb88cfdfSWludzik, Jozef const uint64_t interval, 72dcc4e193SKrzysztof Grobelny ReadingParametersPastVersion metricParams) { 737e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 743eb56865SSzymon Dompke constexpr uint64_t appendLimitDefault = 0; 753eb56865SSzymon Dompke constexpr ReportUpdates reportUpdatesDefault = 7651497a0cSKrzysztof Grobelny ReportUpdates::overwrite; 7751497a0cSKrzysztof Grobelny 7851497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions; 7951497a0cSKrzysztof Grobelny 8051497a0cSKrzysztof Grobelny if (emitsReadingsUpdate) 8151497a0cSKrzysztof Grobelny { 8251497a0cSKrzysztof Grobelny reportActions.emplace_back( 8351497a0cSKrzysztof Grobelny ReportAction::emitsReadingsUpdate); 8451497a0cSKrzysztof Grobelny } 8551497a0cSKrzysztof Grobelny if (logToMetricReportsCollection) 8651497a0cSKrzysztof Grobelny { 8751497a0cSKrzysztof Grobelny reportActions.emplace_back( 8851497a0cSKrzysztof Grobelny ReportAction::logToMetricReportsCollection); 8951497a0cSKrzysztof Grobelny } 9051497a0cSKrzysztof Grobelny 91b8cc78ddSKrzysztof Grobelny return addReport(yield, reportId, reportId, 9251497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 9351497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), 9451497a0cSKrzysztof Grobelny appendLimitDefault, reportUpdatesDefault, 95dcc4e193SKrzysztof Grobelny convertToReadingParameters( 967e098e93SLukasz Kazmierczak std::move(metricParams)), 977e098e93SLukasz Kazmierczak enabledDefault) 98dcc4e193SKrzysztof Grobelny .getPath(); 99dcc4e193SKrzysztof Grobelny }); 100dcc4e193SKrzysztof Grobelny 101dcc4e193SKrzysztof Grobelny dbusIface.register_method( 102dcc4e193SKrzysztof Grobelny "AddReportFutureVersion", 103b8cc78ddSKrzysztof Grobelny [this]( 104b8cc78ddSKrzysztof Grobelny boost::asio::yield_context& yield, 105b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 106dcc4e193SKrzysztof Grobelny const std::string& reportingType, 1073eb56865SSzymon Dompke const std::string& reportUpdates, 10851497a0cSKrzysztof Grobelny const uint64_t appendLimit, 10951497a0cSKrzysztof Grobelny const std::vector<std::string>& reportActions, 110b8cc78ddSKrzysztof Grobelny const uint64_t interval, ReadingParameters metricParams) { 1117e098e93SLukasz Kazmierczak constexpr auto enabledDefault = true; 112b8cc78ddSKrzysztof Grobelny return addReport(yield, reportId, reportName, 11351497a0cSKrzysztof Grobelny utils::toReportingType(reportingType), 11451497a0cSKrzysztof Grobelny utils::transform( 11551497a0cSKrzysztof Grobelny reportActions, 11651497a0cSKrzysztof Grobelny [](const auto& reportAction) { 11751497a0cSKrzysztof Grobelny return utils::toReportAction( 11851497a0cSKrzysztof Grobelny reportAction); 11951497a0cSKrzysztof Grobelny }), 1203eb56865SSzymon Dompke Milliseconds(interval), appendLimit, 12151497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 12251497a0cSKrzysztof Grobelny std::move(metricParams), enabledDefault) 123d2238194SKrzysztof Grobelny .getPath(); 124e2362796SWludzik, Jozef }); 125e2362796SWludzik, Jozef }); 126e2362796SWludzik, Jozef } 127e2362796SWludzik, Jozef 128e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report) 129e2362796SWludzik, Jozef { 130e2362796SWludzik, Jozef reports.erase( 131e2362796SWludzik, Jozef std::remove_if(reports.begin(), reports.end(), 132e2362796SWludzik, Jozef [report](const auto& x) { return report == x.get(); }), 133e2362796SWludzik, Jozef reports.end()); 134e2362796SWludzik, Jozef } 135e2362796SWludzik, Jozef 136dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport( 137b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 138b8cc78ddSKrzysztof Grobelny const ReportingType reportingType, Milliseconds interval, 139cd5b0b7eSAnkita Vilas Gawade const ReportUpdates reportUpdates, const uint64_t appendLimit, 140dcc4e193SKrzysztof Grobelny const std::vector<LabeledMetricParameters>& readingParams) 141e2362796SWludzik, Jozef { 142cb88cfdfSWludzik, Jozef if (reports.size() >= maxReports) 143cb88cfdfSWludzik, Jozef { 144cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 145cb88cfdfSWludzik, Jozef static_cast<int>(std::errc::too_many_files_open), 146cb88cfdfSWludzik, Jozef "Reached maximal report count"); 14764b75a5bSKrzysztof Grobelny } 14864b75a5bSKrzysztof Grobelny 149e6c417cfSKrzysztof Grobelny if (appendLimit > maxAppendLimit && 150e6c417cfSKrzysztof Grobelny appendLimit != std::numeric_limits<uint64_t>::max()) 151cd5b0b7eSAnkita Vilas Gawade { 152cd5b0b7eSAnkita Vilas Gawade throw sdbusplus::exception::SdBusError( 153cd5b0b7eSAnkita Vilas Gawade static_cast<int>(std::errc::invalid_argument), 154cd5b0b7eSAnkita Vilas Gawade "Append limit out of range"); 155cd5b0b7eSAnkita Vilas Gawade } 156cd5b0b7eSAnkita Vilas Gawade 157*973b4bb0SKrzysztof Grobelny if ((reportingType == ReportingType::periodic && interval < minInterval) || 158*973b4bb0SKrzysztof Grobelny (reportingType != ReportingType::periodic && 159*973b4bb0SKrzysztof Grobelny interval != Milliseconds{0})) 160cb88cfdfSWludzik, Jozef { 161cb88cfdfSWludzik, Jozef throw sdbusplus::exception::SdBusError( 162e2362796SWludzik, Jozef static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 163cb88cfdfSWludzik, Jozef } 164bc766b4dSWludzik, Jozef 165cd5b0b7eSAnkita Vilas Gawade size_t metricCount = 0; 166cd5b0b7eSAnkita Vilas Gawade for (auto metricParam : readingParams) 167cd5b0b7eSAnkita Vilas Gawade { 168cd5b0b7eSAnkita Vilas Gawade auto metricParamsVec = 169cd5b0b7eSAnkita Vilas Gawade metricParam.at_label<utils::tstring::SensorPath>(); 170cd5b0b7eSAnkita Vilas Gawade metricCount += metricParamsVec.size(); 171cd5b0b7eSAnkita Vilas Gawade } 172e8fc5751SKrzysztof Grobelny 173cd5b0b7eSAnkita Vilas Gawade if (readingParams.size() > maxNumberMetrics || 174cd5b0b7eSAnkita Vilas Gawade metricCount > maxNumberMetrics) 175bc766b4dSWludzik, Jozef { 176bc766b4dSWludzik, Jozef throw sdbusplus::exception::SdBusError( 177bc766b4dSWludzik, Jozef static_cast<int>(std::errc::argument_list_too_long), 178bc766b4dSWludzik, Jozef "Too many reading parameters"); 179bc766b4dSWludzik, Jozef } 180e8fc5751SKrzysztof Grobelny 181e8fc5751SKrzysztof Grobelny try 182e8fc5751SKrzysztof Grobelny { 183dcc4e193SKrzysztof Grobelny namespace ts = utils::tstring; 184dcc4e193SKrzysztof Grobelny 185dcc4e193SKrzysztof Grobelny for (const LabeledMetricParameters& item : readingParams) 186e8fc5751SKrzysztof Grobelny { 187dcc4e193SKrzysztof Grobelny utils::toOperationType( 188dcc4e193SKrzysztof Grobelny utils::toUnderlying(item.at_label<ts::OperationType>())); 189e8fc5751SKrzysztof Grobelny } 190e8fc5751SKrzysztof Grobelny } 191e8fc5751SKrzysztof Grobelny catch (const std::exception& e) 192e8fc5751SKrzysztof Grobelny { 193e8fc5751SKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 194e8fc5751SKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), e.what()); 195e8fc5751SKrzysztof Grobelny } 196d2238194SKrzysztof Grobelny } 197cb88cfdfSWludzik, Jozef 198d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 199b8cc78ddSKrzysztof Grobelny boost::asio::yield_context& yield, const std::string& reportId, 200b8cc78ddSKrzysztof Grobelny const std::string& reportName, const ReportingType reportingType, 20151497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 20251497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 2037e098e93SLukasz Kazmierczak ReadingParameters metricParams, const bool enabled) 204d2238194SKrzysztof Grobelny { 205dcc4e193SKrzysztof Grobelny auto labeledMetricParams = 206dcc4e193SKrzysztof Grobelny reportFactory->convertMetricParams(yield, metricParams); 207d2238194SKrzysztof Grobelny 208b8cc78ddSKrzysztof Grobelny return addReport(reportId, reportName, reportingType, reportActions, 209b8cc78ddSKrzysztof Grobelny interval, appendLimit, reportUpdates, 210493e62ebSKrzysztof Grobelny std::move(labeledMetricParams), enabled, Readings{}); 211d2238194SKrzysztof Grobelny } 212d2238194SKrzysztof Grobelny 213d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport( 214b8cc78ddSKrzysztof Grobelny const std::string& reportId, const std::string& reportName, 215b8cc78ddSKrzysztof Grobelny const ReportingType reportingType, 21651497a0cSKrzysztof Grobelny const std::vector<ReportAction>& reportActions, Milliseconds interval, 21751497a0cSKrzysztof Grobelny const uint64_t appendLimit, const ReportUpdates reportUpdates, 2187e098e93SLukasz Kazmierczak std::vector<LabeledMetricParameters> labeledMetricParams, 219493e62ebSKrzysztof Grobelny const bool enabled, Readings readings) 220d2238194SKrzysztof Grobelny { 221b8cc78ddSKrzysztof Grobelny const auto existingReportIds = utils::transform( 222b8cc78ddSKrzysztof Grobelny reports, [](const auto& report) { return report->getId(); }); 223b8cc78ddSKrzysztof Grobelny 224a950e42bSKrzysztof Grobelny auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault, 225a950e42bSKrzysztof Grobelny existingReportIds, maxReportIdLength); 226b8cc78ddSKrzysztof Grobelny 227b8cc78ddSKrzysztof Grobelny verifyAddReport(id, name, reportingType, interval, reportUpdates, 228cd5b0b7eSAnkita Vilas Gawade appendLimit, labeledMetricParams); 229d2238194SKrzysztof Grobelny 230493e62ebSKrzysztof Grobelny reports.emplace_back( 231493e62ebSKrzysztof Grobelny reportFactory->make(id, name, reportingType, reportActions, interval, 232493e62ebSKrzysztof Grobelny appendLimit, reportUpdates, *this, *reportStorage, 233493e62ebSKrzysztof Grobelny labeledMetricParams, enabled, std::move(readings))); 234d2238194SKrzysztof Grobelny return *reports.back(); 235cb88cfdfSWludzik, Jozef } 236cb88cfdfSWludzik, Jozef 237e2362796SWludzik, Jozef void ReportManager::loadFromPersistent() 238cb88cfdfSWludzik, Jozef { 239e2362796SWludzik, Jozef std::vector<interfaces::JsonStorage::FilePath> paths = 240e2362796SWludzik, Jozef reportStorage->list(); 241e2362796SWludzik, Jozef 242e2362796SWludzik, Jozef for (const auto& path : paths) 243e2362796SWludzik, Jozef { 244e2362796SWludzik, Jozef std::optional<nlohmann::json> data = reportStorage->load(path); 245e2362796SWludzik, Jozef try 246e2362796SWludzik, Jozef { 247e2362796SWludzik, Jozef size_t version = data->at("Version").get<size_t>(); 248e2362796SWludzik, Jozef if (version != Report::reportVersion) 249e2362796SWludzik, Jozef { 250e2362796SWludzik, Jozef throw std::logic_error("Invalid version"); 251e2362796SWludzik, Jozef } 252b8cc78ddSKrzysztof Grobelny bool enabled = data->at("Enabled").get<bool>(); 253b8cc78ddSKrzysztof Grobelny std::string& id = data->at("Id").get_ref<std::string&>(); 254e2362796SWludzik, Jozef std::string& name = data->at("Name").get_ref<std::string&>(); 25551497a0cSKrzysztof Grobelny 25651497a0cSKrzysztof Grobelny uint32_t reportingType = data->at("ReportingType").get<uint32_t>(); 25751497a0cSKrzysztof Grobelny std::vector<ReportAction> reportActions = utils::transform( 25851497a0cSKrzysztof Grobelny data->at("ReportActions").get<std::vector<uint32_t>>(), 25951497a0cSKrzysztof Grobelny [](const auto reportAction) { 26051497a0cSKrzysztof Grobelny return utils::toReportAction(reportAction); 26151497a0cSKrzysztof Grobelny }); 262e2362796SWludzik, Jozef uint64_t interval = data->at("Interval").get<uint64_t>(); 2633eb56865SSzymon Dompke uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>(); 26451497a0cSKrzysztof Grobelny uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>(); 265d2238194SKrzysztof Grobelny auto readingParameters = 266d2238194SKrzysztof Grobelny data->at("ReadingParameters") 267d2238194SKrzysztof Grobelny .get<std::vector<LabeledMetricParameters>>(); 268e2362796SWludzik, Jozef 269493e62ebSKrzysztof Grobelny Readings readings = {}; 270493e62ebSKrzysztof Grobelny 271493e62ebSKrzysztof Grobelny if (auto it = data->find("MetricValues"); it != data->end()) 272493e62ebSKrzysztof Grobelny { 273493e62ebSKrzysztof Grobelny const auto labeledReadings = it->get<LabeledReadings>(); 274493e62ebSKrzysztof Grobelny readings = utils::toReadings(labeledReadings); 275493e62ebSKrzysztof Grobelny } 276493e62ebSKrzysztof Grobelny 277b8cc78ddSKrzysztof Grobelny addReport(id, name, utils::toReportingType(reportingType), 27851497a0cSKrzysztof Grobelny reportActions, Milliseconds(interval), appendLimit, 27951497a0cSKrzysztof Grobelny utils::toReportUpdates(reportUpdates), 280493e62ebSKrzysztof Grobelny std::move(readingParameters), enabled, 281493e62ebSKrzysztof Grobelny std::move(readings)); 282e2362796SWludzik, Jozef } 283e2362796SWludzik, Jozef catch (const std::exception& e) 284e2362796SWludzik, Jozef { 285e2362796SWludzik, Jozef phosphor::logging::log<phosphor::logging::level::ERR>( 286e2362796SWludzik, Jozef "Failed to load report from storage", 287e2362796SWludzik, Jozef phosphor::logging::entry( 288982c5b5bSWludzik, Jozef "FILENAME=%s", 289e2362796SWludzik, Jozef static_cast<std::filesystem::path>(path).c_str()), 290982c5b5bSWludzik, Jozef phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 291e2362796SWludzik, Jozef reportStorage->remove(path); 292e2362796SWludzik, Jozef } 293e2362796SWludzik, Jozef } 29464b75a5bSKrzysztof Grobelny } 295