summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Add-PUT-and-PATCH-for-MetricReportDefinition.patch
diff options
context:
space:
mode:
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.patch948
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