#include "report_manager.hpp" #include "report.hpp" #include "types/report_types.hpp" #include "utils/conversion.hpp" #include "utils/generate_id.hpp" #include "utils/transform.hpp" #include #include #include #include ReadingParameters convertToReadingParameters(ReadingParametersPastVersion params) { return utils::transform(params, [](const auto& param) { using namespace std::chrono_literals; const auto& [sensorPath, operationType, id, metadata] = param; return ReadingParameters::value_type( std::vector< std::tuple>{ {sensorPath, metadata}}, operationType, id, utils::enumToString(CollectionTimeScope::point), 0u); }); } ReportManager::ReportManager( std::unique_ptr reportFactoryIn, std::unique_ptr reportStorageIn, const std::shared_ptr& objServerIn) : reportFactory(std::move(reportFactoryIn)), reportStorage(std::move(reportStorageIn)), objServer(objServerIn) { reports.reserve(maxReports); loadFromPersistent(); reportManagerIface = objServer->add_unique_interface( reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { dbusIface.register_property_r( "MaxReports", size_t{}, sdbusplus::vtable::property_::const_, [](const auto&) { return maxReports; }); dbusIface.register_property_r( "MaxReportIdLength", size_t{}, sdbusplus::vtable::property_::const_, [](const auto&) { return maxReportIdLength; }); dbusIface.register_property_r( "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_, [](const auto&) -> uint64_t { return minInterval.count(); }); dbusIface.register_property_r( "SupportedOperationTypes", std::vector{}, sdbusplus::vtable::property_::const_, [](const auto&) -> std::vector { return utils::transform( utils::convDataOperationType, [](const auto& item) { return std::string(item.first); }); }); dbusIface.register_method( "AddReport", [this](boost::asio::yield_context& yield, const std::string& reportId, const std::string& reportingType, const bool emitsReadingsUpdate, const bool logToMetricReportsCollection, const uint64_t interval, ReadingParametersPastVersion metricParams) { constexpr auto enabledDefault = true; constexpr uint64_t appendLimitDefault = 0; constexpr ReportUpdates reportUpdatesDefault = ReportUpdates::overwrite; std::vector reportActions; if (emitsReadingsUpdate) { reportActions.emplace_back( ReportAction::emitsReadingsUpdate); } if (logToMetricReportsCollection) { reportActions.emplace_back( ReportAction::logToMetricReportsCollection); } return addReport(yield, reportId, reportId, utils::toReportingType(reportingType), reportActions, Milliseconds(interval), appendLimitDefault, reportUpdatesDefault, convertToReadingParameters( std::move(metricParams)), enabledDefault) .getPath(); }); dbusIface.register_method( "AddReportFutureVersion", [this]( boost::asio::yield_context& yield, const std::string& reportId, const std::string& reportName, const std::string& reportingType, const std::string& reportUpdates, const uint64_t appendLimit, const std::vector& reportActions, const uint64_t interval, ReadingParameters metricParams) { constexpr auto enabledDefault = true; return addReport(yield, reportId, reportName, utils::toReportingType(reportingType), utils::transform( reportActions, [](const auto& reportAction) { return utils::toReportAction( reportAction); }), Milliseconds(interval), appendLimit, utils::toReportUpdates(reportUpdates), std::move(metricParams), enabledDefault) .getPath(); }); }); } void ReportManager::removeReport(const interfaces::Report* report) { reports.erase( std::remove_if(reports.begin(), reports.end(), [report](const auto& x) { return report == x.get(); }), reports.end()); } void ReportManager::verifyAddReport( const std::string& reportId, const std::string& reportName, const ReportingType reportingType, Milliseconds interval, const ReportUpdates reportUpdates, const uint64_t appendLimit, const std::vector& readingParams) { if (reports.size() >= maxReports) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::too_many_files_open), "Reached maximal report count"); } if (appendLimit > maxAppendLimit && appendLimit != std::numeric_limits::max()) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::invalid_argument), "Append limit out of range"); } if ((reportingType == ReportingType::periodic && interval < minInterval) || (reportingType != ReportingType::periodic && interval != Milliseconds{0})) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::invalid_argument), "Invalid interval"); } size_t metricCount = 0; for (auto metricParam : readingParams) { auto metricParamsVec = metricParam.at_label(); metricCount += metricParamsVec.size(); } if (readingParams.size() > maxNumberMetrics || metricCount > maxNumberMetrics) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::argument_list_too_long), "Too many reading parameters"); } try { namespace ts = utils::tstring; for (const LabeledMetricParameters& item : readingParams) { utils::toOperationType( utils::toUnderlying(item.at_label())); } } catch (const std::exception& e) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::invalid_argument), e.what()); } } interfaces::Report& ReportManager::addReport( boost::asio::yield_context& yield, const std::string& reportId, const std::string& reportName, const ReportingType reportingType, const std::vector& reportActions, Milliseconds interval, const uint64_t appendLimit, const ReportUpdates reportUpdates, ReadingParameters metricParams, const bool enabled) { auto labeledMetricParams = reportFactory->convertMetricParams(yield, metricParams); return addReport(reportId, reportName, reportingType, reportActions, interval, appendLimit, reportUpdates, std::move(labeledMetricParams), enabled, Readings{}); } interfaces::Report& ReportManager::addReport( const std::string& reportId, const std::string& reportName, const ReportingType reportingType, const std::vector& reportActions, Milliseconds interval, const uint64_t appendLimit, const ReportUpdates reportUpdates, std::vector labeledMetricParams, const bool enabled, Readings readings) { const auto existingReportIds = utils::transform( reports, [](const auto& report) { return report->getId(); }); auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault, existingReportIds, maxReportIdLength); verifyAddReport(id, name, reportingType, interval, reportUpdates, appendLimit, labeledMetricParams); reports.emplace_back( reportFactory->make(id, name, reportingType, reportActions, interval, appendLimit, reportUpdates, *this, *reportStorage, labeledMetricParams, enabled, std::move(readings))); return *reports.back(); } void ReportManager::loadFromPersistent() { std::vector paths = reportStorage->list(); for (const auto& path : paths) { std::optional data = reportStorage->load(path); try { size_t version = data->at("Version").get(); if (version != Report::reportVersion) { throw std::logic_error("Invalid version"); } bool enabled = data->at("Enabled").get(); std::string& id = data->at("Id").get_ref(); std::string& name = data->at("Name").get_ref(); uint32_t reportingType = data->at("ReportingType").get(); std::vector reportActions = utils::transform( data->at("ReportActions").get>(), [](const auto reportAction) { return utils::toReportAction(reportAction); }); uint64_t interval = data->at("Interval").get(); uint64_t appendLimit = data->at("AppendLimit").get(); uint32_t reportUpdates = data->at("ReportUpdates").get(); auto readingParameters = data->at("ReadingParameters") .get>(); Readings readings = {}; if (auto it = data->find("MetricValues"); it != data->end()) { const auto labeledReadings = it->get(); readings = utils::toReadings(labeledReadings); } addReport(id, name, utils::toReportingType(reportingType), reportActions, Milliseconds(interval), appendLimit, utils::toReportUpdates(reportUpdates), std::move(readingParameters), enabled, std::move(readings)); } catch (const std::exception& e) { phosphor::logging::log( "Failed to load report from storage", phosphor::logging::entry( "FILENAME=%s", static_cast(path).c_str()), phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); reportStorage->remove(path); } } }