diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch | 948 |
1 files changed, 948 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch new file mode 100644 index 000000000..ea409fe09 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch @@ -0,0 +1,948 @@ +From 4c39922af8bf73b13150455166e7bd1fd8645a47 Mon Sep 17 00:00:00 2001 +From: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com> +Date: Fri, 17 Dec 2021 13:02:23 +0100 +Subject: [PATCH] Add PUT and PATCH for MetricReportDefinition + +Support for PUT and PATCH methods is added to Metric Report Definition, +now Report can be replaced by PUT or selected read/write properties can +be modified by PATCH method + +Tested: +- Added new Report via PUT and extracted Report via GET checking if + received data is appropriate +- Added Report via POST, overwrite it via PUT and extracted Report via + GET checking if received data is appropriate +- Added Report via POST, overwrite editable properties via PATCH and + fetched Report via GET checking if received data is properly modified + +Signed-off-by: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com> +Change-Id: If75110a92c55c9e4f2415f0ed4471baa802643ff +--- + redfish-core/lib/metric_report_definition.hpp | 774 ++++++++++++++++-- + 1 file changed, 692 insertions(+), 82 deletions(-) + +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +index 30d83b0..e726c8c 100644 +--- a/redfish-core/lib/metric_report_definition.hpp ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -8,9 +8,9 @@ + #include <boost/container/flat_map.hpp> + #include <dbus_utility.hpp> + #include <registries/privilege_registry.hpp> ++#include <utils/stl_utils.hpp> + + #include <tuple> +-#include <variant> + + namespace redfish + { +@@ -22,6 +22,12 @@ using ReadingParameters = std::vector<std::tuple< + std::vector<std::tuple<sdbusplus::message::object_path, std::string>>, + std::string, std::string, std::string, uint64_t>>; + ++enum class addReportType ++{ ++ create, ++ replace ++}; ++ + std::string toReadfishReportAction(std::string_view action) + { + if (action == "EmitsReadingsUpdate") +@@ -48,6 +54,38 @@ std::string toDbusReportAction(std::string_view action) + return ""; + } + ++inline bool verifyCommonErrors(crow::Response& res, const std::string& id, ++ const boost::system::error_code ec) ++{ ++ if (ec.value() == EBADR || ec == boost::system::errc::host_unreachable) ++ { ++ messages::resourceNotFound(res, "MetricReportDefinition", id); ++ return false; ++ } ++ ++ if (ec == boost::system::errc::file_exists) ++ { ++ messages::resourceAlreadyExists(res, "MetricReportDefinition", "Id", ++ id); ++ return false; ++ } ++ ++ if (ec == boost::system::errc::too_many_files_open) ++ { ++ messages::createLimitReachedForResource(res); ++ return false; ++ } ++ ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "DBUS response error " << ec; ++ messages::internalError(res); ++ return false; ++ } ++ ++ return true; ++} ++ + inline void fillReportDefinition( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id, + const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& +@@ -193,17 +231,17 @@ inline void fillReportDefinition( + } + } + +-struct AddReportArgs ++struct MetricArgs + { +- struct MetricArgs +- { +- std::string id; +- std::vector<std::string> uris; +- std::optional<std::string> collectionFunction; +- std::optional<std::string> collectionTimeScope; +- std::optional<uint64_t> collectionDuration; +- }; ++ std::string id; ++ std::vector<std::string> uris; ++ std::optional<std::string> collectionFunction; ++ std::optional<std::string> collectionTimeScope; ++ std::optional<uint64_t> collectionDuration; ++}; + ++struct AddReportArgs ++{ + std::optional<std::string> id; + std::optional<std::string> name; + std::string reportingType; +@@ -215,22 +253,22 @@ struct AddReportArgs + }; + + inline bool toDbusReportActions(crow::Response& res, +- const std::vector<std::string>& actions, +- AddReportArgs& args) ++ const std::vector<std::string>& redfishActions, ++ std::vector<std::string>& dbusActions) + { + size_t index = 0; +- for (const auto& action : actions) ++ for (const auto& redfishAction : redfishActions) + { +- std::string dbusReportAction = toDbusReportAction(action); ++ std::string dbusAction = toDbusReportAction(redfishAction); + +- if (dbusReportAction.empty()) ++ if (dbusAction.empty()) + { + messages::propertyValueNotInList( +- res, action, "ReportActions/" + std::to_string(index)); ++ res, redfishAction, "ReportActions/" + std::to_string(index)); + return false; + } + +- args.reportActions.emplace_back(std::move(dbusReportAction)); ++ dbusActions.emplace_back(std::move(dbusAction)); + index++; + } + return true; +@@ -259,7 +297,7 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + return false; + } + +- if (!toDbusReportActions(res, reportActions, args)) ++ if (!toDbusReportActions(res, reportActions, args.reportActions)) + { + return false; + } +@@ -294,7 +332,7 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + for (auto& m : metrics) + { + std::optional<std::string> collectionDurationStr; +- AddReportArgs::MetricArgs metricArgs; ++ MetricArgs metricArgs; + if (!json_util::readJson( + m, res, "MetricId", metricArgs.id, "MetricProperties", + metricArgs.uris, "CollectionFunction", +@@ -329,7 +367,7 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + + inline bool getChassisSensorNode( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, +- const std::vector<AddReportArgs::MetricArgs>& metrics, ++ const std::vector<MetricArgs>& metrics, + boost::container::flat_set<std::pair<std::string, std::string>>& matched) + { + for (const auto& metric : metrics) +@@ -363,13 +401,122 @@ inline bool getChassisSensorNode( + return true; + } + ++inline bool getReadingParametersFromMetrics( ++ crow::Response& res, const std::vector<MetricArgs>& metrics, ++ const boost::container::flat_map<std::string, std::string>& uriToDbus, ++ ReadingParameters& readingParams) ++{ ++ if (metrics.empty()) ++ { ++ return true; ++ } ++ ++ readingParams.reserve(metrics.size()); ++ for (const auto& metric : metrics) ++ { ++ std::vector<std::tuple<sdbusplus::message::object_path, std::string>> ++ sensorParams; ++ sensorParams.reserve(metric.uris.size()); ++ ++ for (size_t i = 0; i < metric.uris.size(); i++) ++ { ++ const std::string& uri = metric.uris[i]; ++ auto el = uriToDbus.find(uri); ++ if (el == uriToDbus.end()) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to find DBus sensor corresponding to URI " ++ << uri; ++ messages::propertyValueNotInList( ++ res, uri, "MetricProperties/" + std::to_string(i)); ++ return false; ++ } ++ ++ const std::string& dbusPath = el->second; ++ sensorParams.emplace_back(dbusPath, uri); ++ } ++ ++ readingParams.emplace_back( ++ std::move(sensorParams), metric.collectionFunction.value_or(""), ++ metric.id, metric.collectionTimeScope.value_or(""), ++ metric.collectionDuration.value_or(0U)); ++ } ++ ++ return true; ++} ++ ++class UpdateMetrics ++{ ++ public: ++ UpdateMetrics(const std::string& idIn, std::vector<MetricArgs> metricsIn, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) : ++ asyncResp(asyncResp), ++ id(idIn), metrics{std::move(metricsIn)} ++ {} ++ ++ ~UpdateMetrics() ++ { ++ setReadingParams(); ++ } ++ ++ UpdateMetrics(const UpdateMetrics&) = delete; ++ UpdateMetrics(UpdateMetrics&&) = delete; ++ UpdateMetrics& operator=(const UpdateMetrics&) = delete; ++ UpdateMetrics& operator=(UpdateMetrics&&) = delete; ++ ++ void insert(const boost::container::flat_map<std::string, std::string>& el) ++ { ++ uriToDbus.insert(el.begin(), el.end()); ++ } ++ ++ void setReadingParams() ++ { ++ if (asyncResp->res.result() != boost::beast::http::status::ok) ++ { ++ return; ++ } ++ ++ if (!getReadingParametersFromMetrics(asyncResp->res, metrics, uriToDbus, ++ readingParams)) ++ { ++ return; ++ } ++ ++ const std::shared_ptr<bmcweb::AsyncResp> aResp = asyncResp; ++ crow::connections::systemBus->async_method_call( ++ [aResp, id = id](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ messages::propertyValueModified(aResp->res, "Metrics", ++ "Updated"); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", ++ "ReadingParametersFutureVersion", ++ dbus::utility::DbusVariantType{readingParams}); ++ } ++ ++ private: ++ const std::shared_ptr<bmcweb::AsyncResp> asyncResp; ++ std::string id; ++ std::vector<MetricArgs> metrics; ++ boost::container::flat_map<std::string, std::string> uriToDbus{}; ++ ReadingParameters readingParams{}; ++}; ++ + class AddReport + { + public: + AddReport(AddReportArgs argsIn, +- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) : ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ addReportType type) : + asyncResp(asyncResp), +- args{std::move(argsIn)} ++ args{std::move(argsIn)}, type(type) + {} + ~AddReport() + { +@@ -378,7 +525,7 @@ class AddReport + return; + } + +- telemetry::ReadingParameters readingParams; ++ ReadingParameters readingParams; + readingParams.reserve(args.metrics.size()); + + for (auto& metric : args.metrics) +@@ -412,22 +559,12 @@ class AddReport + std::move(metric.id), metric.collectionTimeScope.value_or(""), + metric.collectionDuration.value_or(0U)); + } ++ + const std::shared_ptr<bmcweb::AsyncResp> aResp = asyncResp; + crow::connections::systemBus->async_method_call( +- [aResp, id = args.id.value_or(""), +- uriToDbus = std::move(uriToDbus)]( +- const boost::system::error_code ec, const std::string&) { +- if (ec == boost::system::errc::file_exists) +- { +- messages::resourceAlreadyExists( +- aResp->res, "MetricReportDefinition", "Id", id); +- return; +- } +- if (ec == boost::system::errc::too_many_files_open) +- { +- messages::createLimitReachedForResource(aResp->res); +- return; +- } ++ [aResp, id = args.id.value_or(""), uriToDbus = std::move(uriToDbus), ++ type = type](const boost::system::error_code ec, ++ const std::string&) { + if (ec == boost::system::errc::argument_list_too_long) + { + nlohmann::json metricProperties = nlohmann::json::array(); +@@ -440,16 +577,22 @@ class AddReport + "MetricProperties"); + return; + } +- if (ec) ++ ++ if (!verifyCommonErrors(aResp->res, id, ec)) + { +- messages::internalError(aResp->res); +- BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; + return; + } + +- messages::created(aResp->res); ++ if (type == addReportType::create) ++ { ++ messages::created(aResp->res); ++ } ++ else ++ { ++ messages::success(aResp->res); ++ } + }, +- telemetry::service, "/xyz/openbmc_project/Telemetry/Reports", ++ service, "/xyz/openbmc_project/Telemetry/Reports", + "xyz.openbmc_project.Telemetry.ReportManager", + "AddReportFutureVersion", + "TelemetryService/" + args.id.value_or(""), args.name.value_or(""), +@@ -471,8 +614,491 @@ class AddReport + private: + const std::shared_ptr<bmcweb::AsyncResp> asyncResp; + AddReportArgs args; ++ const addReportType type; + boost::container::flat_map<std::string, std::string> uriToDbus{}; + }; ++ ++inline void setReportEnabled(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, bool enabled) ++{ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, ++ enabled](const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& currEnabledVar) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ const bool* currEnabled = std::get_if<bool>(&currEnabledVar); ++ if (currEnabled == nullptr || *currEnabled == enabled) ++ { ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, enabled](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ messages::propertyValueModified( ++ aResp->res, "MetricReportDefinitionEnabled", ++ enabled ? "True" : "False"); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", "Enabled", ++ dbus::utility::DbusVariantType{enabled}); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "Enabled"); ++} ++ ++inline void setReportType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, const std::string& type) ++{ ++ if (type != "Periodic" && type != "OnChange" && type != "OnRequest") ++ { ++ messages::propertyValueNotInList(aResp->res, type, ++ "MetricReportDefinitionType"); ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, type](const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& currTypeVar) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ const std::string* currType = ++ std::get_if<std::string>(&currTypeVar); ++ if (currType == nullptr || *currType == type) ++ { ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, type](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ messages::propertyValueModified( ++ aResp->res, "MetricReportDefinitionType", type); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", "ReportingType", ++ dbus::utility::DbusVariantType{type}); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "ReportingType"); ++} ++ ++inline void setReportUpdates(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, const std::string& updates) ++{ ++ if (updates != "Overwrite" && updates != "AppendWrapsWhenFull" && ++ updates != "AppendStopsWhenFull") ++ { ++ messages::propertyValueNotInList(aResp->res, updates, "ReportUpdates"); ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, ++ updates](const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& currUpdatesVar) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ const std::string* currUpdates = ++ std::get_if<std::string>(&currUpdatesVar); ++ if (currUpdates == nullptr || *currUpdates == updates) ++ { ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, updates](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ messages::propertyValueModified(aResp->res, "ReportUpdates", ++ updates); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", "ReportUpdates", ++ dbus::utility::DbusVariantType{updates}); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "ReportUpdates"); ++} ++ ++inline void setReportActions(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, ++ std::vector<std::string>& redfishActions) ++{ ++ if (redfishActions.size() > 1) ++ { ++ stl_utils::removeDuplicate(redfishActions); ++ } ++ ++ std::vector<std::string> newDbusActions; ++ if (!toDbusReportActions(aResp->res, redfishActions, newDbusActions)) ++ { ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, redfishActions = std::move(redfishActions), ++ newDbusActions = std::move(newDbusActions)]( ++ const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& currDbusActionsVar) mutable { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ std::vector<std::string> currDbusActions; ++ if (const std::vector<std::string>* tmp = ++ std::get_if<std::vector<std::string>>(&currDbusActionsVar)) ++ { ++ currDbusActions = *tmp; ++ } ++ else ++ { ++ messages::internalError(aResp->res); ++ return; ++ } ++ ++ if (newDbusActions.size() == currDbusActions.size()) ++ { ++ std::sort(newDbusActions.begin(), newDbusActions.end()); ++ if (newDbusActions == currDbusActions) ++ { ++ return; ++ } ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, ++ redfishActions](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ std::string redfishActionsStr; ++ for (const auto& redfishAction : redfishActions) ++ { ++ redfishActionsStr += redfishAction + std::string(" "); ++ } ++ if (!redfishActionsStr.empty()) ++ { ++ redfishActionsStr.pop_back(); ++ } ++ messages::propertyValueModified(aResp->res, "ReportActions", ++ redfishActionsStr); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", "ReportActions", ++ dbus::utility::DbusVariantType{newDbusActions}); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "ReportActions"); ++} ++ ++inline void setReportInterval(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, nlohmann::json& schedule) ++{ ++ crow::connections::systemBus->async_method_call( ++ [aResp, schedule = std::move(schedule), ++ id](const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& typeVar) mutable { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ const std::string* reportingType = ++ std::get_if<std::string>(&typeVar); ++ if (reportingType == nullptr || *reportingType != "Periodic") ++ { ++ return; ++ } ++ ++ std::string durationStr; ++ if (!json_util::readJson(schedule, aResp->res, "RecurrenceInterval", ++ durationStr)) ++ { ++ return; ++ } ++ ++ std::optional<std::chrono::milliseconds> durationNum = ++ time_utils::fromDurationString(durationStr); ++ uint64_t interval = static_cast<uint64_t>(durationNum->count()); ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, interval, durationStr]( ++ const boost::system::error_code ec, ++ const dbus::utility::DbusVariantType& currIntervalVar) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ const uint64_t* currInterval = ++ std::get_if<uint64_t>(&currIntervalVar); ++ if (currInterval == nullptr || *currInterval == interval) ++ { ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, ++ durationStr](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ ++ messages::propertyValueModified( ++ aResp->res, "RecurrenceInterval", durationStr); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/" ++ "TelemetryService/" + ++ id, ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Telemetry.Report", "Interval", ++ dbus::utility::DbusVariantType{interval}); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "Interval"); ++ }, ++ "xyz.openbmc_project.Telemetry", ++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id, ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.Telemetry.Report", "ReportingType"); ++} ++ ++inline void setReportMetrics(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id, ++ std::vector<nlohmann::json>& metricJsons) ++{ ++ std::vector<MetricArgs> metrics; ++ metrics.reserve(metricJsons.size()); ++ ++ for (auto& m : metricJsons) ++ { ++ MetricArgs metricArgs; ++ std::optional<std::string> collectionDurationStr; ++ if (!json_util::readJson( ++ m, aResp->res, "MetricId", metricArgs.id, "MetricProperties", ++ metricArgs.uris, "CollectionFunction", ++ metricArgs.collectionFunction, "CollectionTimeScope", ++ metricArgs.collectionTimeScope, "CollectionDuration", ++ collectionDurationStr)) ++ { ++ return; ++ } ++ ++ if (collectionDurationStr) ++ { ++ std::optional<std::chrono::milliseconds> duration = ++ time_utils::fromDurationString(*collectionDurationStr); ++ ++ if (!duration || duration->count() < 0) ++ { ++ messages::propertyValueIncorrect( ++ aResp->res, "CollectionDuration", *collectionDurationStr); ++ return; ++ } ++ ++ metricArgs.collectionDuration = ++ static_cast<uint64_t>(duration->count()); ++ } ++ ++ metrics.emplace_back(std::move(metricArgs)); ++ } ++ ++ boost::container::flat_set<std::pair<std::string, std::string>> ++ chassisSensors; ++ if (!getChassisSensorNode(aResp, metrics, chassisSensors)) ++ { ++ return; ++ } ++ ++ auto updateMetricsReq = ++ std::make_shared<UpdateMetrics>(id, std::move(metrics), aResp); ++ ++ for (const auto& [chassis, sensorType] : chassisSensors) ++ { ++ retrieveUriToDbusMap( ++ chassis, sensorType, ++ [aResp, updateMetricsReq]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map<std::string, std::string>& ++ uriToDbus) { ++ if (status != boost::beast::http::status::ok) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to retrieve URI to dbus sensors map with err " ++ << static_cast<unsigned>(status); ++ return; ++ } ++ updateMetricsReq->insert(uriToDbus); ++ }); ++ } ++} ++ ++inline void handleReportPatch(const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id) ++{ ++ std::optional<bool> enabled; ++ std::optional<std::string> type; ++ std::optional<std::string> updates; ++ std::optional<std::vector<std::string>> actions; ++ std::optional<nlohmann::json> schedule; ++ std::optional<std::vector<nlohmann::json>> metrics; ++ ++ if (!json_util::readJsonPatch( ++ req, aResp->res, "MetricReportDefinitionEnabled", enabled, ++ "Schedule", schedule, "ReportActions", actions, "Metrics", metrics, ++ "MetricReportDefinitionType", type, "ReportUpdates", updates)) ++ { ++ return; ++ } ++ ++ if (enabled) ++ { ++ setReportEnabled(aResp, id, *enabled); ++ } ++ if (type) ++ { ++ setReportType(aResp, id, *type); ++ } ++ if (updates) ++ { ++ setReportUpdates(aResp, id, *updates); ++ } ++ if (actions) ++ { ++ setReportActions(aResp, id, *actions); ++ } ++ if (schedule) ++ { ++ setReportInterval(aResp, id, *schedule); ++ } ++ if (metrics) ++ { ++ setReportMetrics(aResp, id, *metrics); ++ } ++} ++ ++inline void handleReportPut(const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id) ++{ ++ AddReportArgs args; ++ if (!getUserParameters(aResp->res, req, args)) ++ { ++ return; ++ } ++ ++ boost::container::flat_set<std::pair<std::string, std::string>> ++ chassisSensors; ++ if (!getChassisSensorNode(aResp, args.metrics, chassisSensors)) ++ { ++ return; ++ } ++ ++ const std::string reportPath = getDbusReportPath(id); ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id, args = std::move(args), ++ chassisSensors = ++ std::move(chassisSensors)](const boost::system::error_code ec) { ++ addReportType addReportMode = addReportType::replace; ++ if (ec) ++ { ++ if (ec.value() != EBADR) ++ { ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ messages::internalError(aResp->res); ++ return; ++ } ++ BMCWEB_LOG_INFO << "Report not found, creating new report: " ++ << id; ++ addReportMode = addReportType::create; ++ } ++ ++ auto addReportReq = ++ std::make_shared<AddReport>(args, aResp, addReportMode); ++ for (const auto& [chassis, sensorType] : chassisSensors) ++ { ++ retrieveUriToDbusMap( ++ chassis, sensorType, ++ [aResp, ++ addReportReq](const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ if (status != boost::beast::http::status::ok) ++ { ++ BMCWEB_LOG_ERROR ++ << "Failed to retrieve URI to dbus " ++ "sensors map with err " ++ << static_cast<unsigned>(status); ++ return; ++ } ++ addReportReq->insert(uriToDbus); ++ }); ++ } ++ }, ++ service, reportPath, "xyz.openbmc_project.Object.Delete", "Delete"); ++} ++ ++inline void handleReportDelete(const std::shared_ptr<bmcweb::AsyncResp>& aResp, ++ const std::string& id) ++{ ++ const std::string reportPath = getDbusReportPath(id); ++ ++ crow::connections::systemBus->async_method_call( ++ [aResp, id](const boost::system::error_code ec) { ++ if (!verifyCommonErrors(aResp->res, id, ec)) ++ { ++ return; ++ } ++ aResp->res.result(boost::beast::http::status::no_content); ++ }, ++ service, reportPath, "xyz.openbmc_project.Object.Delete", "Delete"); ++} + } // namespace telemetry + + inline void requestRoutesMetricReportDefinitionCollection(App& app) +@@ -517,7 +1143,7 @@ inline void requestRoutesMetricReportDefinitionCollection(App& app) + } + + auto addReportReq = std::make_shared<telemetry::AddReport>( +- std::move(args), asyncResp); ++ std::move(args), asyncResp, telemetry::addReportType::create); + for (const auto& [chassis, sensorType] : chassisSensors) + { + retrieveUriToDbusMap( +@@ -554,17 +1180,9 @@ inline void requestRoutesMetricReportDefinition(App& app) + const std::vector<std::pair< + std::string, dbus::utility::DbusVariantType>>& + properties) { +- if (ec.value() == EBADR || +- ec == boost::system::errc::host_unreachable) ++ if (!redfish::telemetry::verifyCommonErrors( ++ asyncResp->res, id, ec)) + { +- messages::resourceNotFound( +- asyncResp->res, "MetricReportDefinition", id); +- return; +- } +- if (ec) +- { +- BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; +- messages::internalError(asyncResp->res); + return; + } + +@@ -578,40 +1196,32 @@ inline void requestRoutesMetricReportDefinition(App& app) + + BMCWEB_ROUTE(app, + "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") +- .privileges(redfish::privileges::deleteMetricReportDefinitionCollection) ++ .privileges(redfish::privileges::deleteMetricReportDefinition) + .methods(boost::beast::http::verb::delete_)( + [](const crow::Request&, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, +- const std::string& id) +- +- { +- const std::string reportPath = telemetry::getDbusReportPath(id); +- +- crow::connections::systemBus->async_method_call( +- [asyncResp, id](const boost::system::error_code ec) { +- /* +- * boost::system::errc and std::errc are missing value +- * for EBADR error that is defined in Linux. +- */ +- if (ec.value() == EBADR) +- { +- messages::resourceNotFound( +- asyncResp->res, "MetricReportDefinition", id); +- return; +- } ++ const std::string& id) { ++ telemetry::handleReportDelete(asyncResp, id); ++ }); + +- if (ec) +- { +- BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; +- messages::internalError(asyncResp->res); +- return; +- } ++ BMCWEB_ROUTE(app, ++ "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") ++ .privileges(redfish::privileges::putMetricReportDefinition) ++ .methods(boost::beast::http::verb::put)( ++ [](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const std::string& id) { ++ telemetry::handleReportPut(req, asyncResp, id); ++ }); + +- asyncResp->res.result( +- boost::beast::http::status::no_content); +- }, +- telemetry::service, reportPath, +- "xyz.openbmc_project.Object.Delete", "Delete"); ++ BMCWEB_ROUTE(app, ++ "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") ++ .privileges(redfish::privileges::patchMetricReportDefinition) ++ .methods(boost::beast::http::verb::patch)( ++ [](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const std::string& id) { ++ telemetry::handleReportPatch(req, asyncResp, id); + }); + } + } // namespace redfish +-- +2.25.1 |