xref: /openbmc/bmcweb/features/redfish/lib/metric_report_definition.hpp (revision 177612aaa0633cf9d5aef0b763a43135cf552d9b)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3081ebf06SWludzik, Jozef #pragma once
4081ebf06SWludzik, Jozef 
53ccb3adbSEd Tanous #include "app.hpp"
6d7857201SEd Tanous #include "async_resp.hpp"
7d7857201SEd Tanous #include "dbus_singleton.hpp"
83ccb3adbSEd Tanous #include "dbus_utility.hpp"
9d7857201SEd Tanous #include "error_messages.hpp"
10479e899dSKrzysztof Grobelny #include "generated/enums/metric_report_definition.hpp"
11539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
12d7857201SEd Tanous #include "http_request.hpp"
13d7857201SEd Tanous #include "http_response.hpp"
14d7857201SEd Tanous #include "logging.hpp"
153ccb3adbSEd Tanous #include "query.hpp"
163ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
174dbb8aeaSWludzik, Jozef #include "sensors.hpp"
183ccb3adbSEd Tanous #include "utils/collection.hpp"
193ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
205b90429aSEd Tanous #include "utils/json_utils.hpp"
21081ebf06SWludzik, Jozef #include "utils/telemetry_utils.hpp"
22081ebf06SWludzik, Jozef #include "utils/time_utils.hpp"
23081ebf06SWludzik, Jozef 
24d7857201SEd Tanous #include <asm-generic/errno.h>
25d7857201SEd Tanous #include <systemd/sd-bus.h>
26d7857201SEd Tanous 
27d7857201SEd Tanous #include <boost/asio/post.hpp>
28d7857201SEd Tanous #include <boost/beast/http/field.hpp>
29d7857201SEd Tanous #include <boost/beast/http/status.hpp>
30d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
314dbb8aeaSWludzik, Jozef #include <boost/container/flat_map.hpp>
32d7857201SEd Tanous #include <boost/container/flat_set.hpp>
33ef4c65b7SEd Tanous #include <boost/url/format.hpp>
34d7857201SEd Tanous #include <boost/url/url.hpp>
35d7857201SEd Tanous #include <nlohmann/json.hpp>
36d7857201SEd Tanous #include <sdbusplus/message.hpp>
37d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
3889474494SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
394dbb8aeaSWludzik, Jozef 
407a1dbc48SGeorge Liu #include <array>
41d7857201SEd Tanous #include <chrono>
42d7857201SEd Tanous #include <cstddef>
43d7857201SEd Tanous #include <cstdint>
44d7857201SEd Tanous #include <functional>
45d7857201SEd Tanous #include <limits>
46fe04d49cSNan Zhou #include <map>
47d7857201SEd Tanous #include <memory>
48f19ab44aSSzymon Dompke #include <optional>
49f19ab44aSSzymon Dompke #include <span>
50f19ab44aSSzymon Dompke #include <string>
517a1dbc48SGeorge Liu #include <string_view>
52081ebf06SWludzik, Jozef #include <tuple>
53f19ab44aSSzymon Dompke #include <utility>
54081ebf06SWludzik, Jozef #include <variant>
55f19ab44aSSzymon Dompke #include <vector>
56081ebf06SWludzik, Jozef 
57081ebf06SWludzik, Jozef namespace redfish
58081ebf06SWludzik, Jozef {
59081ebf06SWludzik, Jozef 
60081ebf06SWludzik, Jozef namespace telemetry
61081ebf06SWludzik, Jozef {
62081ebf06SWludzik, Jozef 
63479e899dSKrzysztof Grobelny using ReadingParameters = std::vector<std::tuple<
64479e899dSKrzysztof Grobelny     std::vector<std::tuple<sdbusplus::message::object_path, std::string>>,
65479e899dSKrzysztof Grobelny     std::string, std::string, uint64_t>>;
66479e899dSKrzysztof Grobelny 
679e6c388aSLukasz Kazmierczak inline bool verifyCommonErrors(crow::Response& res, const std::string& id,
689e6c388aSLukasz Kazmierczak                                const boost::system::error_code& ec)
699e6c388aSLukasz Kazmierczak {
709e6c388aSLukasz Kazmierczak     if (ec.value() == EBADR || ec == boost::system::errc::host_unreachable)
719e6c388aSLukasz Kazmierczak     {
729e6c388aSLukasz Kazmierczak         messages::resourceNotFound(res, "MetricReportDefinition", id);
739e6c388aSLukasz Kazmierczak         return false;
749e6c388aSLukasz Kazmierczak     }
759e6c388aSLukasz Kazmierczak 
769e6c388aSLukasz Kazmierczak     if (ec == boost::system::errc::file_exists)
779e6c388aSLukasz Kazmierczak     {
789e6c388aSLukasz Kazmierczak         messages::resourceAlreadyExists(res, "MetricReportDefinition", "Id",
799e6c388aSLukasz Kazmierczak                                         id);
809e6c388aSLukasz Kazmierczak         return false;
819e6c388aSLukasz Kazmierczak     }
829e6c388aSLukasz Kazmierczak 
839e6c388aSLukasz Kazmierczak     if (ec == boost::system::errc::too_many_files_open)
849e6c388aSLukasz Kazmierczak     {
859e6c388aSLukasz Kazmierczak         messages::createLimitReachedForResource(res);
869e6c388aSLukasz Kazmierczak         return false;
879e6c388aSLukasz Kazmierczak     }
889e6c388aSLukasz Kazmierczak 
899e6c388aSLukasz Kazmierczak     if (ec)
909e6c388aSLukasz Kazmierczak     {
919e6c388aSLukasz Kazmierczak         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
929e6c388aSLukasz Kazmierczak         messages::internalError(res);
939e6c388aSLukasz Kazmierczak         return false;
949e6c388aSLukasz Kazmierczak     }
959e6c388aSLukasz Kazmierczak 
969e6c388aSLukasz Kazmierczak     return true;
979e6c388aSLukasz Kazmierczak }
989e6c388aSLukasz Kazmierczak 
99504af5a0SPatrick Williams inline metric_report_definition::ReportActionsEnum toRedfishReportAction(
100504af5a0SPatrick Williams     std::string_view dbusValue)
101479e899dSKrzysztof Grobelny {
102479e899dSKrzysztof Grobelny     if (dbusValue ==
103479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate")
104479e899dSKrzysztof Grobelny     {
105479e899dSKrzysztof Grobelny         return metric_report_definition::ReportActionsEnum::RedfishEvent;
106479e899dSKrzysztof Grobelny     }
107479e899dSKrzysztof Grobelny     if (dbusValue ==
108479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection")
109479e899dSKrzysztof Grobelny     {
110479e899dSKrzysztof Grobelny         return metric_report_definition::ReportActionsEnum::
111479e899dSKrzysztof Grobelny             LogToMetricReportsCollection;
112479e899dSKrzysztof Grobelny     }
113479e899dSKrzysztof Grobelny     return metric_report_definition::ReportActionsEnum::Invalid;
114479e899dSKrzysztof Grobelny }
115479e899dSKrzysztof Grobelny 
116479e899dSKrzysztof Grobelny inline std::string toDbusReportAction(std::string_view redfishValue)
117479e899dSKrzysztof Grobelny {
118479e899dSKrzysztof Grobelny     if (redfishValue == "RedfishEvent")
119479e899dSKrzysztof Grobelny     {
120479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate";
121479e899dSKrzysztof Grobelny     }
122479e899dSKrzysztof Grobelny     if (redfishValue == "LogToMetricReportsCollection")
123479e899dSKrzysztof Grobelny     {
124479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection";
125479e899dSKrzysztof Grobelny     }
126479e899dSKrzysztof Grobelny     return "";
127479e899dSKrzysztof Grobelny }
128479e899dSKrzysztof Grobelny 
129479e899dSKrzysztof Grobelny inline metric_report_definition::MetricReportDefinitionType
130479e899dSKrzysztof Grobelny     toRedfishReportingType(std::string_view dbusValue)
131479e899dSKrzysztof Grobelny {
132479e899dSKrzysztof Grobelny     if (dbusValue ==
133479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange")
134479e899dSKrzysztof Grobelny     {
135479e899dSKrzysztof Grobelny         return metric_report_definition::MetricReportDefinitionType::OnChange;
136479e899dSKrzysztof Grobelny     }
137479e899dSKrzysztof Grobelny     if (dbusValue ==
138479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest")
139479e899dSKrzysztof Grobelny     {
140479e899dSKrzysztof Grobelny         return metric_report_definition::MetricReportDefinitionType::OnRequest;
141479e899dSKrzysztof Grobelny     }
142479e899dSKrzysztof Grobelny     if (dbusValue ==
143479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic")
144479e899dSKrzysztof Grobelny     {
145479e899dSKrzysztof Grobelny         return metric_report_definition::MetricReportDefinitionType::Periodic;
146479e899dSKrzysztof Grobelny     }
147479e899dSKrzysztof Grobelny     return metric_report_definition::MetricReportDefinitionType::Invalid;
148479e899dSKrzysztof Grobelny }
149479e899dSKrzysztof Grobelny 
150479e899dSKrzysztof Grobelny inline std::string toDbusReportingType(std::string_view redfishValue)
151479e899dSKrzysztof Grobelny {
152479e899dSKrzysztof Grobelny     if (redfishValue == "OnChange")
153479e899dSKrzysztof Grobelny     {
154479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange";
155479e899dSKrzysztof Grobelny     }
156479e899dSKrzysztof Grobelny     if (redfishValue == "OnRequest")
157479e899dSKrzysztof Grobelny     {
158479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest";
159479e899dSKrzysztof Grobelny     }
160479e899dSKrzysztof Grobelny     if (redfishValue == "Periodic")
161479e899dSKrzysztof Grobelny     {
162479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic";
163479e899dSKrzysztof Grobelny     }
164479e899dSKrzysztof Grobelny     return "";
165479e899dSKrzysztof Grobelny }
166479e899dSKrzysztof Grobelny 
167479e899dSKrzysztof Grobelny inline metric_report_definition::CollectionTimeScope
168479e899dSKrzysztof Grobelny     toRedfishCollectionTimeScope(std::string_view dbusValue)
169479e899dSKrzysztof Grobelny {
170479e899dSKrzysztof Grobelny     if (dbusValue ==
171479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point")
172479e899dSKrzysztof Grobelny     {
173479e899dSKrzysztof Grobelny         return metric_report_definition::CollectionTimeScope::Point;
174479e899dSKrzysztof Grobelny     }
175479e899dSKrzysztof Grobelny     if (dbusValue ==
176479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval")
177479e899dSKrzysztof Grobelny     {
178479e899dSKrzysztof Grobelny         return metric_report_definition::CollectionTimeScope::Interval;
179479e899dSKrzysztof Grobelny     }
180479e899dSKrzysztof Grobelny     if (dbusValue ==
181479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval")
182479e899dSKrzysztof Grobelny     {
183479e899dSKrzysztof Grobelny         return metric_report_definition::CollectionTimeScope::StartupInterval;
184479e899dSKrzysztof Grobelny     }
185479e899dSKrzysztof Grobelny     return metric_report_definition::CollectionTimeScope::Invalid;
186479e899dSKrzysztof Grobelny }
187479e899dSKrzysztof Grobelny 
188479e899dSKrzysztof Grobelny inline std::string toDbusCollectionTimeScope(std::string_view redfishValue)
189479e899dSKrzysztof Grobelny {
190479e899dSKrzysztof Grobelny     if (redfishValue == "Point")
191479e899dSKrzysztof Grobelny     {
192479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point";
193479e899dSKrzysztof Grobelny     }
194479e899dSKrzysztof Grobelny     if (redfishValue == "Interval")
195479e899dSKrzysztof Grobelny     {
196479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval";
197479e899dSKrzysztof Grobelny     }
198479e899dSKrzysztof Grobelny     if (redfishValue == "StartupInterval")
199479e899dSKrzysztof Grobelny     {
200479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval";
201479e899dSKrzysztof Grobelny     }
202479e899dSKrzysztof Grobelny     return "";
203479e899dSKrzysztof Grobelny }
204479e899dSKrzysztof Grobelny 
205504af5a0SPatrick Williams inline metric_report_definition::ReportUpdatesEnum toRedfishReportUpdates(
206504af5a0SPatrick Williams     std::string_view dbusValue)
207479e899dSKrzysztof Grobelny {
208479e899dSKrzysztof Grobelny     if (dbusValue ==
209479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite")
210479e899dSKrzysztof Grobelny     {
211479e899dSKrzysztof Grobelny         return metric_report_definition::ReportUpdatesEnum::Overwrite;
212479e899dSKrzysztof Grobelny     }
213479e899dSKrzysztof Grobelny     if (dbusValue ==
214479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull")
215479e899dSKrzysztof Grobelny     {
216479e899dSKrzysztof Grobelny         return metric_report_definition::ReportUpdatesEnum::AppendWrapsWhenFull;
217479e899dSKrzysztof Grobelny     }
218479e899dSKrzysztof Grobelny     if (dbusValue ==
219479e899dSKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull")
220479e899dSKrzysztof Grobelny     {
221479e899dSKrzysztof Grobelny         return metric_report_definition::ReportUpdatesEnum::AppendStopsWhenFull;
222479e899dSKrzysztof Grobelny     }
223479e899dSKrzysztof Grobelny     return metric_report_definition::ReportUpdatesEnum::Invalid;
224479e899dSKrzysztof Grobelny }
225479e899dSKrzysztof Grobelny 
226479e899dSKrzysztof Grobelny inline std::string toDbusReportUpdates(std::string_view redfishValue)
227479e899dSKrzysztof Grobelny {
228479e899dSKrzysztof Grobelny     if (redfishValue == "Overwrite")
229479e899dSKrzysztof Grobelny     {
230479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite";
231479e899dSKrzysztof Grobelny     }
232479e899dSKrzysztof Grobelny     if (redfishValue == "AppendWrapsWhenFull")
233479e899dSKrzysztof Grobelny     {
234479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull";
235479e899dSKrzysztof Grobelny     }
236479e899dSKrzysztof Grobelny     if (redfishValue == "AppendStopsWhenFull")
237479e899dSKrzysztof Grobelny     {
238479e899dSKrzysztof Grobelny         return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull";
239479e899dSKrzysztof Grobelny     }
240479e899dSKrzysztof Grobelny     return "";
241479e899dSKrzysztof Grobelny }
242081ebf06SWludzik, Jozef 
243f19ab44aSSzymon Dompke inline std::optional<nlohmann::json::array_t> getLinkedTriggers(
244f19ab44aSSzymon Dompke     std::span<const sdbusplus::message::object_path> triggerPaths)
245f19ab44aSSzymon Dompke {
246f19ab44aSSzymon Dompke     nlohmann::json::array_t triggers;
247f19ab44aSSzymon Dompke 
248f19ab44aSSzymon Dompke     for (const sdbusplus::message::object_path& path : triggerPaths)
249f19ab44aSSzymon Dompke     {
250f19ab44aSSzymon Dompke         if (path.parent_path() !=
251f19ab44aSSzymon Dompke             "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService")
252f19ab44aSSzymon Dompke         {
25362598e31SEd Tanous             BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}",
25462598e31SEd Tanous                              path.str);
255f19ab44aSSzymon Dompke             return std::nullopt;
256f19ab44aSSzymon Dompke         }
257f19ab44aSSzymon Dompke 
258f19ab44aSSzymon Dompke         std::string id = path.filename();
259f19ab44aSSzymon Dompke         if (id.empty())
260f19ab44aSSzymon Dompke         {
26162598e31SEd Tanous             BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}",
26262598e31SEd Tanous                              path.str);
263f19ab44aSSzymon Dompke             return std::nullopt;
264f19ab44aSSzymon Dompke         }
265f19ab44aSSzymon Dompke         nlohmann::json::object_t trigger;
266f19ab44aSSzymon Dompke         trigger["@odata.id"] =
267f19ab44aSSzymon Dompke             boost::urls::format("/redfish/v1/TelemetryService/Triggers/{}", id);
268f19ab44aSSzymon Dompke         triggers.emplace_back(std::move(trigger));
269f19ab44aSSzymon Dompke     }
270f19ab44aSSzymon Dompke 
271f19ab44aSSzymon Dompke     return triggers;
272f19ab44aSSzymon Dompke }
273f19ab44aSSzymon Dompke 
274bd79bce8SPatrick Williams inline void fillReportDefinition(
275bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
276479e899dSKrzysztof Grobelny     const dbus::utility::DBusPropertiesMap& properties)
277081ebf06SWludzik, Jozef {
278479e899dSKrzysztof Grobelny     std::vector<std::string> reportActions;
279479e899dSKrzysztof Grobelny     ReadingParameters readingParams;
280479e899dSKrzysztof Grobelny     std::string reportingType;
281479e899dSKrzysztof Grobelny     std::string reportUpdates;
282479e899dSKrzysztof Grobelny     std::string name;
283479e899dSKrzysztof Grobelny     uint64_t appendLimit = 0;
284479e899dSKrzysztof Grobelny     uint64_t interval = 0;
285479e899dSKrzysztof Grobelny     bool enabled = false;
286f19ab44aSSzymon Dompke     std::vector<sdbusplus::message::object_path> triggers;
28789474494SKrzysztof Grobelny 
28889474494SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
289479e899dSKrzysztof Grobelny         dbus_utils::UnpackErrorPrinter(), properties, "ReportingType",
290479e899dSKrzysztof Grobelny         reportingType, "Interval", interval, "ReportActions", reportActions,
291479e899dSKrzysztof Grobelny         "ReportUpdates", reportUpdates, "AppendLimit", appendLimit,
292f19ab44aSSzymon Dompke         "ReadingParameters", readingParams, "Name", name, "Enabled", enabled,
293f19ab44aSSzymon Dompke         "Triggers", triggers);
29489474494SKrzysztof Grobelny 
29589474494SKrzysztof Grobelny     if (!success)
296081ebf06SWludzik, Jozef     {
297081ebf06SWludzik, Jozef         messages::internalError(asyncResp->res);
298081ebf06SWludzik, Jozef         return;
299081ebf06SWludzik, Jozef     }
300081ebf06SWludzik, Jozef 
301479e899dSKrzysztof Grobelny     metric_report_definition::MetricReportDefinitionType redfishReportingType =
302479e899dSKrzysztof Grobelny         toRedfishReportingType(reportingType);
303479e899dSKrzysztof Grobelny     if (redfishReportingType ==
304479e899dSKrzysztof Grobelny         metric_report_definition::MetricReportDefinitionType::Invalid)
305081ebf06SWludzik, Jozef     {
306479e899dSKrzysztof Grobelny         messages::internalError(asyncResp->res);
307479e899dSKrzysztof Grobelny         return;
308081ebf06SWludzik, Jozef     }
30989474494SKrzysztof Grobelny 
310479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["MetricReportDefinitionType"] =
311479e899dSKrzysztof Grobelny         redfishReportingType;
312479e899dSKrzysztof Grobelny 
313f19ab44aSSzymon Dompke     std::optional<nlohmann::json::array_t> linkedTriggers =
314f19ab44aSSzymon Dompke         getLinkedTriggers(triggers);
315f19ab44aSSzymon Dompke     if (!linkedTriggers)
316f19ab44aSSzymon Dompke     {
317f19ab44aSSzymon Dompke         messages::internalError(asyncResp->res);
318f19ab44aSSzymon Dompke         return;
319f19ab44aSSzymon Dompke     }
320f19ab44aSSzymon Dompke 
321f19ab44aSSzymon Dompke     asyncResp->res.jsonValue["Links"]["Triggers"] = std::move(*linkedTriggers);
322f19ab44aSSzymon Dompke 
323479e899dSKrzysztof Grobelny     nlohmann::json::array_t redfishReportActions;
324479e899dSKrzysztof Grobelny     for (const std::string& action : reportActions)
325081ebf06SWludzik, Jozef     {
326479e899dSKrzysztof Grobelny         metric_report_definition::ReportActionsEnum redfishAction =
327479e899dSKrzysztof Grobelny             toRedfishReportAction(action);
328479e899dSKrzysztof Grobelny         if (redfishAction ==
329479e899dSKrzysztof Grobelny             metric_report_definition::ReportActionsEnum::Invalid)
330479e899dSKrzysztof Grobelny         {
331479e899dSKrzysztof Grobelny             messages::internalError(asyncResp->res);
332479e899dSKrzysztof Grobelny             return;
333081ebf06SWludzik, Jozef         }
334081ebf06SWludzik, Jozef 
335479e899dSKrzysztof Grobelny         redfishReportActions.emplace_back(redfishAction);
336479e899dSKrzysztof Grobelny     }
337479e899dSKrzysztof Grobelny 
338479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["ReportActions"] = std::move(redfishReportActions);
339479e899dSKrzysztof Grobelny 
340479e899dSKrzysztof Grobelny     nlohmann::json::array_t metrics = nlohmann::json::array();
341479e899dSKrzysztof Grobelny     for (const auto& [sensorData, collectionFunction, collectionTimeScope,
342479e899dSKrzysztof Grobelny                       collectionDuration] : readingParams)
34389474494SKrzysztof Grobelny     {
344479e899dSKrzysztof Grobelny         nlohmann::json::array_t metricProperties;
345479e899dSKrzysztof Grobelny 
346479e899dSKrzysztof Grobelny         for (const auto& [sensorPath, sensorMetadata] : sensorData)
347081ebf06SWludzik, Jozef         {
348479e899dSKrzysztof Grobelny             metricProperties.emplace_back(sensorMetadata);
349479e899dSKrzysztof Grobelny         }
350479e899dSKrzysztof Grobelny 
351613dabeaSEd Tanous         nlohmann::json::object_t metric;
352479e899dSKrzysztof Grobelny 
353479e899dSKrzysztof Grobelny         metric_report_definition::CalculationAlgorithmEnum
354479e899dSKrzysztof Grobelny             redfishCollectionFunction =
355479e899dSKrzysztof Grobelny                 telemetry::toRedfishCollectionFunction(collectionFunction);
356479e899dSKrzysztof Grobelny         if (redfishCollectionFunction ==
357479e899dSKrzysztof Grobelny             metric_report_definition::CalculationAlgorithmEnum::Invalid)
358479e899dSKrzysztof Grobelny         {
359479e899dSKrzysztof Grobelny             messages::internalError(asyncResp->res);
360479e899dSKrzysztof Grobelny             return;
361479e899dSKrzysztof Grobelny         }
362479e899dSKrzysztof Grobelny         metric["CollectionFunction"] = redfishCollectionFunction;
363479e899dSKrzysztof Grobelny 
364479e899dSKrzysztof Grobelny         metric_report_definition::CollectionTimeScope
365479e899dSKrzysztof Grobelny             redfishCollectionTimeScope =
366479e899dSKrzysztof Grobelny                 toRedfishCollectionTimeScope(collectionTimeScope);
367479e899dSKrzysztof Grobelny         if (redfishCollectionTimeScope ==
368479e899dSKrzysztof Grobelny             metric_report_definition::CollectionTimeScope::Invalid)
369479e899dSKrzysztof Grobelny         {
370479e899dSKrzysztof Grobelny             messages::internalError(asyncResp->res);
371479e899dSKrzysztof Grobelny             return;
372479e899dSKrzysztof Grobelny         }
373479e899dSKrzysztof Grobelny         metric["CollectionTimeScope"] = redfishCollectionTimeScope;
374479e899dSKrzysztof Grobelny 
375479e899dSKrzysztof Grobelny         metric["MetricProperties"] = std::move(metricProperties);
376479e899dSKrzysztof Grobelny         metric["CollectionDuration"] = time_utils::toDurationString(
377479e899dSKrzysztof Grobelny             std::chrono::milliseconds(collectionDuration));
378b2ba3072SPatrick Williams         metrics.emplace_back(std::move(metric));
379081ebf06SWludzik, Jozef     }
380479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["Metrics"] = std::move(metrics);
381479e899dSKrzysztof Grobelny 
382479e899dSKrzysztof Grobelny     if (enabled)
383479e899dSKrzysztof Grobelny     {
384539d8c6bSEd Tanous         asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
385479e899dSKrzysztof Grobelny     }
386479e899dSKrzysztof Grobelny     else
387479e899dSKrzysztof Grobelny     {
388539d8c6bSEd Tanous         asyncResp->res.jsonValue["Status"]["State"] = resource::State::Disabled;
38989474494SKrzysztof Grobelny     }
39089474494SKrzysztof Grobelny 
391479e899dSKrzysztof Grobelny     metric_report_definition::ReportUpdatesEnum redfishReportUpdates =
392479e899dSKrzysztof Grobelny         toRedfishReportUpdates(reportUpdates);
393479e899dSKrzysztof Grobelny     if (redfishReportUpdates ==
394479e899dSKrzysztof Grobelny         metric_report_definition::ReportUpdatesEnum::Invalid)
39589474494SKrzysztof Grobelny     {
396479e899dSKrzysztof Grobelny         messages::internalError(asyncResp->res);
397479e899dSKrzysztof Grobelny         return;
39889474494SKrzysztof Grobelny     }
399479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["ReportUpdates"] = redfishReportUpdates;
40089474494SKrzysztof Grobelny 
401479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["MetricReportDefinitionEnabled"] = enabled;
402479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["AppendLimit"] = appendLimit;
403479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["Name"] = name;
404081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
405479e899dSKrzysztof Grobelny         time_utils::toDurationString(std::chrono::milliseconds(interval));
406479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["@odata.type"] =
407479e899dSKrzysztof Grobelny         "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
408479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
409479e899dSKrzysztof Grobelny         "/redfish/v1/TelemetryService/MetricReportDefinitions/{}", id);
410479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["Id"] = id;
411479e899dSKrzysztof Grobelny     asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = boost::urls::format(
412479e899dSKrzysztof Grobelny         "/redfish/v1/TelemetryService/MetricReports/{}", id);
41389474494SKrzysztof Grobelny }
41489474494SKrzysztof Grobelny 
4154dbb8aeaSWludzik, Jozef struct AddReportArgs
4164dbb8aeaSWludzik, Jozef {
417479e899dSKrzysztof Grobelny     struct MetricArgs
418479e899dSKrzysztof Grobelny     {
419479e899dSKrzysztof Grobelny         std::vector<std::string> uris;
420479e899dSKrzysztof Grobelny         std::string collectionFunction;
421479e899dSKrzysztof Grobelny         std::string collectionTimeScope;
422479e899dSKrzysztof Grobelny         uint64_t collectionDuration = 0;
423479e899dSKrzysztof Grobelny     };
424479e899dSKrzysztof Grobelny 
425479e899dSKrzysztof Grobelny     std::string id;
4264dbb8aeaSWludzik, Jozef     std::string name;
4274dbb8aeaSWludzik, Jozef     std::string reportingType;
428479e899dSKrzysztof Grobelny     std::string reportUpdates;
429479e899dSKrzysztof Grobelny     uint64_t appendLimit = std::numeric_limits<uint64_t>::max();
430479e899dSKrzysztof Grobelny     std::vector<std::string> reportActions;
431479e899dSKrzysztof Grobelny     uint64_t interval = std::numeric_limits<uint64_t>::max();
432479e899dSKrzysztof Grobelny     std::vector<MetricArgs> metrics;
433479e899dSKrzysztof Grobelny     bool metricReportDefinitionEnabled = true;
4344dbb8aeaSWludzik, Jozef };
4354dbb8aeaSWludzik, Jozef 
4364dbb8aeaSWludzik, Jozef inline bool toDbusReportActions(crow::Response& res,
437479e899dSKrzysztof Grobelny                                 const std::vector<std::string>& actions,
4389e6c388aSLukasz Kazmierczak                                 std::vector<std::string>& outReportActions)
4394dbb8aeaSWludzik, Jozef {
4404dbb8aeaSWludzik, Jozef     size_t index = 0;
441479e899dSKrzysztof Grobelny     for (const std::string& action : actions)
4424dbb8aeaSWludzik, Jozef     {
443479e899dSKrzysztof Grobelny         std::string dbusReportAction = toDbusReportAction(action);
444479e899dSKrzysztof Grobelny         if (dbusReportAction.empty())
4454dbb8aeaSWludzik, Jozef         {
4469e6c388aSLukasz Kazmierczak             messages::propertyValueNotInList(
4479e6c388aSLukasz Kazmierczak                 res, action, "ReportActions/" + std::to_string(index));
4484dbb8aeaSWludzik, Jozef             return false;
4494dbb8aeaSWludzik, Jozef         }
450479e899dSKrzysztof Grobelny 
4519e6c388aSLukasz Kazmierczak         outReportActions.emplace_back(std::move(dbusReportAction));
4524dbb8aeaSWludzik, Jozef         index++;
4534dbb8aeaSWludzik, Jozef     }
4544dbb8aeaSWludzik, Jozef     return true;
4554dbb8aeaSWludzik, Jozef }
4564dbb8aeaSWludzik, Jozef 
457b14f357fSEd Tanous inline bool getUserMetric(crow::Response& res, nlohmann::json::object_t& metric,
458479e899dSKrzysztof Grobelny                           AddReportArgs::MetricArgs& metricArgs)
459479e899dSKrzysztof Grobelny {
460479e899dSKrzysztof Grobelny     std::optional<std::vector<std::string>> uris;
461479e899dSKrzysztof Grobelny     std::optional<std::string> collectionDurationStr;
462479e899dSKrzysztof Grobelny     std::optional<std::string> collectionFunction;
463479e899dSKrzysztof Grobelny     std::optional<std::string> collectionTimeScopeStr;
464479e899dSKrzysztof Grobelny 
465afc474aeSMyung Bae     if (!json_util::readJsonObject(                        //
466afc474aeSMyung Bae             metric, res,                                   //
467afc474aeSMyung Bae             "CollectionDuration", collectionDurationStr,   //
468afc474aeSMyung Bae             "CollectionFunction", collectionFunction,      //
469afc474aeSMyung Bae             "CollectionTimeScope", collectionTimeScopeStr, //
470afc474aeSMyung Bae             "MetricProperties", uris                       //
471afc474aeSMyung Bae             ))
472479e899dSKrzysztof Grobelny     {
473479e899dSKrzysztof Grobelny         return false;
474479e899dSKrzysztof Grobelny     }
475479e899dSKrzysztof Grobelny 
476479e899dSKrzysztof Grobelny     if (uris)
477479e899dSKrzysztof Grobelny     {
478479e899dSKrzysztof Grobelny         metricArgs.uris = std::move(*uris);
479479e899dSKrzysztof Grobelny     }
480479e899dSKrzysztof Grobelny 
481479e899dSKrzysztof Grobelny     if (collectionFunction)
482479e899dSKrzysztof Grobelny     {
483479e899dSKrzysztof Grobelny         std::string dbusCollectionFunction =
484479e899dSKrzysztof Grobelny             telemetry::toDbusCollectionFunction(*collectionFunction);
485479e899dSKrzysztof Grobelny         if (dbusCollectionFunction.empty())
486479e899dSKrzysztof Grobelny         {
487479e899dSKrzysztof Grobelny             messages::propertyValueIncorrect(res, "CollectionFunction",
488479e899dSKrzysztof Grobelny                                              *collectionFunction);
489479e899dSKrzysztof Grobelny             return false;
490479e899dSKrzysztof Grobelny         }
491479e899dSKrzysztof Grobelny         metricArgs.collectionFunction = std::move(dbusCollectionFunction);
492479e899dSKrzysztof Grobelny     }
493479e899dSKrzysztof Grobelny 
494479e899dSKrzysztof Grobelny     if (collectionTimeScopeStr)
495479e899dSKrzysztof Grobelny     {
496479e899dSKrzysztof Grobelny         std::string dbusCollectionTimeScope =
497479e899dSKrzysztof Grobelny             toDbusCollectionTimeScope(*collectionTimeScopeStr);
498479e899dSKrzysztof Grobelny         if (dbusCollectionTimeScope.empty())
499479e899dSKrzysztof Grobelny         {
500479e899dSKrzysztof Grobelny             messages::propertyValueIncorrect(res, "CollectionTimeScope",
501479e899dSKrzysztof Grobelny                                              *collectionTimeScopeStr);
502479e899dSKrzysztof Grobelny             return false;
503479e899dSKrzysztof Grobelny         }
504479e899dSKrzysztof Grobelny         metricArgs.collectionTimeScope = std::move(dbusCollectionTimeScope);
505479e899dSKrzysztof Grobelny     }
506479e899dSKrzysztof Grobelny 
507479e899dSKrzysztof Grobelny     if (collectionDurationStr)
508479e899dSKrzysztof Grobelny     {
509479e899dSKrzysztof Grobelny         std::optional<std::chrono::milliseconds> duration =
510479e899dSKrzysztof Grobelny             time_utils::fromDurationString(*collectionDurationStr);
511479e899dSKrzysztof Grobelny 
512479e899dSKrzysztof Grobelny         if (!duration || duration->count() < 0)
513479e899dSKrzysztof Grobelny         {
514479e899dSKrzysztof Grobelny             messages::propertyValueIncorrect(res, "CollectionDuration",
515479e899dSKrzysztof Grobelny                                              *collectionDurationStr);
516479e899dSKrzysztof Grobelny             return false;
517479e899dSKrzysztof Grobelny         }
518479e899dSKrzysztof Grobelny 
519479e899dSKrzysztof Grobelny         metricArgs.collectionDuration =
520479e899dSKrzysztof Grobelny             static_cast<uint64_t>(duration->count());
521479e899dSKrzysztof Grobelny     }
522479e899dSKrzysztof Grobelny 
523479e899dSKrzysztof Grobelny     return true;
524479e899dSKrzysztof Grobelny }
525479e899dSKrzysztof Grobelny 
526479e899dSKrzysztof Grobelny inline bool getUserMetrics(crow::Response& res,
527b14f357fSEd Tanous                            std::span<nlohmann::json::object_t> metrics,
528479e899dSKrzysztof Grobelny                            std::vector<AddReportArgs::MetricArgs>& result)
529479e899dSKrzysztof Grobelny {
530479e899dSKrzysztof Grobelny     result.reserve(metrics.size());
531479e899dSKrzysztof Grobelny 
532b14f357fSEd Tanous     for (nlohmann::json::object_t& m : metrics)
533479e899dSKrzysztof Grobelny     {
534479e899dSKrzysztof Grobelny         AddReportArgs::MetricArgs metricArgs;
535479e899dSKrzysztof Grobelny 
536479e899dSKrzysztof Grobelny         if (!getUserMetric(res, m, metricArgs))
537479e899dSKrzysztof Grobelny         {
538479e899dSKrzysztof Grobelny             return false;
539479e899dSKrzysztof Grobelny         }
540479e899dSKrzysztof Grobelny 
541479e899dSKrzysztof Grobelny         result.emplace_back(std::move(metricArgs));
542479e899dSKrzysztof Grobelny     }
543479e899dSKrzysztof Grobelny 
544479e899dSKrzysztof Grobelny     return true;
545479e899dSKrzysztof Grobelny }
546479e899dSKrzysztof Grobelny 
5474dbb8aeaSWludzik, Jozef inline bool getUserParameters(crow::Response& res, const crow::Request& req,
5484dbb8aeaSWludzik, Jozef                               AddReportArgs& args)
5494dbb8aeaSWludzik, Jozef {
550479e899dSKrzysztof Grobelny     std::optional<std::string> id;
551479e899dSKrzysztof Grobelny     std::optional<std::string> name;
552479e899dSKrzysztof Grobelny     std::optional<std::string> reportingTypeStr;
553479e899dSKrzysztof Grobelny     std::optional<std::string> reportUpdatesStr;
554479e899dSKrzysztof Grobelny     std::optional<uint64_t> appendLimit;
555479e899dSKrzysztof Grobelny     std::optional<bool> metricReportDefinitionEnabled;
556b14f357fSEd Tanous     std::optional<std::vector<nlohmann::json::object_t>> metrics;
557479e899dSKrzysztof Grobelny     std::optional<std::vector<std::string>> reportActionsStr;
558b14f357fSEd Tanous     std::optional<std::string> scheduleDurationStr;
559479e899dSKrzysztof Grobelny 
560afc474aeSMyung Bae     if (!json_util::readJsonPatch(                                          //
561afc474aeSMyung Bae             req, res,                                                       //
562afc474aeSMyung Bae             "AppendLimit", appendLimit,                                     //
563afc474aeSMyung Bae             "Id", id,                                                       //
564afc474aeSMyung Bae             "MetricReportDefinitionEnabled", metricReportDefinitionEnabled, //
565afc474aeSMyung Bae             "MetricReportDefinitionType", reportingTypeStr,                 //
566afc474aeSMyung Bae             "Metrics", metrics,                                             //
567afc474aeSMyung Bae             "Name", name,                                                   //
568afc474aeSMyung Bae             "ReportActions", reportActionsStr,                              //
569afc474aeSMyung Bae             "ReportUpdates", reportUpdatesStr,                              //
570afc474aeSMyung Bae             "Schedule/RecurrenceInterval", scheduleDurationStr              //
571afc474aeSMyung Bae             ))
5724dbb8aeaSWludzik, Jozef     {
5734dbb8aeaSWludzik, Jozef         return false;
5744dbb8aeaSWludzik, Jozef     }
5754dbb8aeaSWludzik, Jozef 
576479e899dSKrzysztof Grobelny     if (id)
577479e899dSKrzysztof Grobelny     {
578479e899dSKrzysztof Grobelny         constexpr const char* allowedCharactersInId =
5794dbb8aeaSWludzik, Jozef             "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
580479e899dSKrzysztof Grobelny         if (id->empty() ||
581479e899dSKrzysztof Grobelny             id->find_first_not_of(allowedCharactersInId) != std::string::npos)
5824dbb8aeaSWludzik, Jozef         {
583479e899dSKrzysztof Grobelny             messages::propertyValueIncorrect(res, "Id", *id);
5844dbb8aeaSWludzik, Jozef             return false;
5854dbb8aeaSWludzik, Jozef         }
586479e899dSKrzysztof Grobelny         args.id = *id;
587479e899dSKrzysztof Grobelny     }
5884dbb8aeaSWludzik, Jozef 
589479e899dSKrzysztof Grobelny     if (name)
5904dbb8aeaSWludzik, Jozef     {
591479e899dSKrzysztof Grobelny         args.name = *name;
592479e899dSKrzysztof Grobelny     }
593479e899dSKrzysztof Grobelny 
594479e899dSKrzysztof Grobelny     if (reportingTypeStr)
595479e899dSKrzysztof Grobelny     {
596479e899dSKrzysztof Grobelny         std::string dbusReportingType = toDbusReportingType(*reportingTypeStr);
597479e899dSKrzysztof Grobelny         if (dbusReportingType.empty())
598479e899dSKrzysztof Grobelny         {
599479e899dSKrzysztof Grobelny             messages::propertyValueNotInList(res, *reportingTypeStr,
6004dbb8aeaSWludzik, Jozef                                              "MetricReportDefinitionType");
6014dbb8aeaSWludzik, Jozef             return false;
6024dbb8aeaSWludzik, Jozef         }
603479e899dSKrzysztof Grobelny         args.reportingType = dbusReportingType;
604479e899dSKrzysztof Grobelny     }
6054dbb8aeaSWludzik, Jozef 
606479e899dSKrzysztof Grobelny     if (reportUpdatesStr)
607479e899dSKrzysztof Grobelny     {
608479e899dSKrzysztof Grobelny         std::string dbusReportUpdates = toDbusReportUpdates(*reportUpdatesStr);
609479e899dSKrzysztof Grobelny         if (dbusReportUpdates.empty())
610479e899dSKrzysztof Grobelny         {
611479e899dSKrzysztof Grobelny             messages::propertyValueNotInList(res, *reportUpdatesStr,
612479e899dSKrzysztof Grobelny                                              "ReportUpdates");
613479e899dSKrzysztof Grobelny             return false;
614479e899dSKrzysztof Grobelny         }
615479e899dSKrzysztof Grobelny         args.reportUpdates = dbusReportUpdates;
616479e899dSKrzysztof Grobelny     }
617479e899dSKrzysztof Grobelny 
618479e899dSKrzysztof Grobelny     if (appendLimit)
619479e899dSKrzysztof Grobelny     {
620479e899dSKrzysztof Grobelny         args.appendLimit = *appendLimit;
621479e899dSKrzysztof Grobelny     }
622479e899dSKrzysztof Grobelny 
623479e899dSKrzysztof Grobelny     if (metricReportDefinitionEnabled)
624479e899dSKrzysztof Grobelny     {
625479e899dSKrzysztof Grobelny         args.metricReportDefinitionEnabled = *metricReportDefinitionEnabled;
626479e899dSKrzysztof Grobelny     }
627479e899dSKrzysztof Grobelny 
628479e899dSKrzysztof Grobelny     if (reportActionsStr)
629479e899dSKrzysztof Grobelny     {
6309e6c388aSLukasz Kazmierczak         if (!toDbusReportActions(res, *reportActionsStr, args.reportActions))
6314dbb8aeaSWludzik, Jozef         {
6324dbb8aeaSWludzik, Jozef             return false;
6334dbb8aeaSWludzik, Jozef         }
634479e899dSKrzysztof Grobelny     }
6354dbb8aeaSWludzik, Jozef 
636479e899dSKrzysztof Grobelny     if (reportingTypeStr == "Periodic")
6374dbb8aeaSWludzik, Jozef     {
638b14f357fSEd Tanous         if (!scheduleDurationStr)
6394dbb8aeaSWludzik, Jozef         {
6404dbb8aeaSWludzik, Jozef             messages::createFailedMissingReqProperties(res, "Schedule");
6414dbb8aeaSWludzik, Jozef             return false;
6424dbb8aeaSWludzik, Jozef         }
6434dbb8aeaSWludzik, Jozef 
6444dbb8aeaSWludzik, Jozef         std::optional<std::chrono::milliseconds> durationNum =
645b14f357fSEd Tanous             time_utils::fromDurationString(*scheduleDurationStr);
646479e899dSKrzysztof Grobelny         if (!durationNum || durationNum->count() < 0)
6474dbb8aeaSWludzik, Jozef         {
6484dbb8aeaSWludzik, Jozef             messages::propertyValueIncorrect(res, "RecurrenceInterval",
649b14f357fSEd Tanous                                              *scheduleDurationStr);
6504dbb8aeaSWludzik, Jozef             return false;
6514dbb8aeaSWludzik, Jozef         }
6524dbb8aeaSWludzik, Jozef         args.interval = static_cast<uint64_t>(durationNum->count());
6534dbb8aeaSWludzik, Jozef     }
6544dbb8aeaSWludzik, Jozef 
655479e899dSKrzysztof Grobelny     if (metrics)
6564dbb8aeaSWludzik, Jozef     {
657479e899dSKrzysztof Grobelny         if (!getUserMetrics(res, *metrics, args.metrics))
6584dbb8aeaSWludzik, Jozef         {
6594dbb8aeaSWludzik, Jozef             return false;
6604dbb8aeaSWludzik, Jozef         }
6614dbb8aeaSWludzik, Jozef     }
6624dbb8aeaSWludzik, Jozef 
6634dbb8aeaSWludzik, Jozef     return true;
6644dbb8aeaSWludzik, Jozef }
6654dbb8aeaSWludzik, Jozef 
666ca1600c1SSzymon Dompke inline bool getChassisSensorNodeFromMetrics(
6678d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
668479e899dSKrzysztof Grobelny     std::span<const AddReportArgs::MetricArgs> metrics,
6694dbb8aeaSWludzik, Jozef     boost::container::flat_set<std::pair<std::string, std::string>>& matched)
6704dbb8aeaSWludzik, Jozef {
671ca1600c1SSzymon Dompke     for (const auto& metric : metrics)
6724dbb8aeaSWludzik, Jozef     {
673479e899dSKrzysztof Grobelny         std::optional<IncorrectMetricUri> error =
674479e899dSKrzysztof Grobelny             getChassisSensorNode(metric.uris, matched);
675ca1600c1SSzymon Dompke         if (error)
6764dbb8aeaSWludzik, Jozef         {
677bd79bce8SPatrick Williams             messages::propertyValueIncorrect(
678bd79bce8SPatrick Williams                 asyncResp->res, error->uri,
679bd79bce8SPatrick Williams                 "MetricProperties/" + std::to_string(error->index));
6804dbb8aeaSWludzik, Jozef             return false;
6814dbb8aeaSWludzik, Jozef         }
6824dbb8aeaSWludzik, Jozef     }
6834dbb8aeaSWludzik, Jozef     return true;
6844dbb8aeaSWludzik, Jozef }
6854dbb8aeaSWludzik, Jozef 
686ba498310SKrzysztof Grobelny inline std::string toRedfishProperty(std::string_view dbusMessage)
687ba498310SKrzysztof Grobelny {
688ba498310SKrzysztof Grobelny     if (dbusMessage == "Id")
689ba498310SKrzysztof Grobelny     {
690ba498310SKrzysztof Grobelny         return "Id";
691ba498310SKrzysztof Grobelny     }
692ba498310SKrzysztof Grobelny     if (dbusMessage == "Name")
693ba498310SKrzysztof Grobelny     {
694ba498310SKrzysztof Grobelny         return "Name";
695ba498310SKrzysztof Grobelny     }
696ba498310SKrzysztof Grobelny     if (dbusMessage == "ReportingType")
697ba498310SKrzysztof Grobelny     {
698ba498310SKrzysztof Grobelny         return "MetricReportDefinitionType";
699ba498310SKrzysztof Grobelny     }
700ba498310SKrzysztof Grobelny     if (dbusMessage == "AppendLimit")
701ba498310SKrzysztof Grobelny     {
702ba498310SKrzysztof Grobelny         return "AppendLimit";
703ba498310SKrzysztof Grobelny     }
704ba498310SKrzysztof Grobelny     if (dbusMessage == "ReportActions")
705ba498310SKrzysztof Grobelny     {
706ba498310SKrzysztof Grobelny         return "ReportActions";
707ba498310SKrzysztof Grobelny     }
708ba498310SKrzysztof Grobelny     if (dbusMessage == "Interval")
709ba498310SKrzysztof Grobelny     {
710ba498310SKrzysztof Grobelny         return "RecurrenceInterval";
711ba498310SKrzysztof Grobelny     }
712ba498310SKrzysztof Grobelny     if (dbusMessage == "ReportUpdates")
713ba498310SKrzysztof Grobelny     {
714ba498310SKrzysztof Grobelny         return "ReportUpdates";
715ba498310SKrzysztof Grobelny     }
716ba498310SKrzysztof Grobelny     if (dbusMessage == "ReadingParameters")
717ba498310SKrzysztof Grobelny     {
718ba498310SKrzysztof Grobelny         return "Metrics";
719ba498310SKrzysztof Grobelny     }
720ba498310SKrzysztof Grobelny     return "";
721ba498310SKrzysztof Grobelny }
722ba498310SKrzysztof Grobelny 
723ba498310SKrzysztof Grobelny inline bool handleParamError(crow::Response& res, const char* errorMessage,
724ba498310SKrzysztof Grobelny                              std::string_view key)
725ba498310SKrzysztof Grobelny {
726ba498310SKrzysztof Grobelny     if (errorMessage == nullptr)
727ba498310SKrzysztof Grobelny     {
728ba498310SKrzysztof Grobelny         BMCWEB_LOG_ERROR("errorMessage was null");
729ba498310SKrzysztof Grobelny         return true;
730ba498310SKrzysztof Grobelny     }
731ba498310SKrzysztof Grobelny     std::string_view errorMessageSv(errorMessage);
732ba498310SKrzysztof Grobelny     if (errorMessageSv.starts_with(key))
733ba498310SKrzysztof Grobelny     {
734ba498310SKrzysztof Grobelny         std::string redfishProperty = toRedfishProperty(key);
735ba498310SKrzysztof Grobelny         if (redfishProperty.empty())
736ba498310SKrzysztof Grobelny         {
737ba498310SKrzysztof Grobelny             // Getting here means most possibly that toRedfishProperty has
738ba498310SKrzysztof Grobelny             // incomplete implementation. Return internal error for now.
739ba498310SKrzysztof Grobelny             BMCWEB_LOG_ERROR("{} has no corresponding Redfish property", key);
740ba498310SKrzysztof Grobelny             messages::internalError(res);
741ba498310SKrzysztof Grobelny             return false;
742ba498310SKrzysztof Grobelny         }
743ba498310SKrzysztof Grobelny         messages::propertyValueError(res, redfishProperty);
744ba498310SKrzysztof Grobelny         return false;
745ba498310SKrzysztof Grobelny     }
746ba498310SKrzysztof Grobelny 
747ba498310SKrzysztof Grobelny     return true;
748ba498310SKrzysztof Grobelny }
749ba498310SKrzysztof Grobelny 
750ba498310SKrzysztof Grobelny inline void afterAddReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
751ba498310SKrzysztof Grobelny                            const AddReportArgs& args,
752ba498310SKrzysztof Grobelny                            const boost::system::error_code& ec,
753ba498310SKrzysztof Grobelny                            const sdbusplus::message_t& msg)
754ba498310SKrzysztof Grobelny {
755ba498310SKrzysztof Grobelny     if (!ec)
756ba498310SKrzysztof Grobelny     {
757ba498310SKrzysztof Grobelny         messages::created(asyncResp->res);
758ba498310SKrzysztof Grobelny         return;
759ba498310SKrzysztof Grobelny     }
760ba498310SKrzysztof Grobelny 
761ba498310SKrzysztof Grobelny     if (ec == boost::system::errc::invalid_argument)
762ba498310SKrzysztof Grobelny     {
763ba498310SKrzysztof Grobelny         const sd_bus_error* errorMessage = msg.get_error();
764ba498310SKrzysztof Grobelny         if (errorMessage != nullptr)
765ba498310SKrzysztof Grobelny         {
766ba498310SKrzysztof Grobelny             for (const auto& arg :
767ba498310SKrzysztof Grobelny                  {"Id", "Name", "ReportingType", "AppendLimit", "ReportActions",
768ba498310SKrzysztof Grobelny                   "Interval", "ReportUpdates", "ReadingParameters"})
769ba498310SKrzysztof Grobelny             {
770ba498310SKrzysztof Grobelny                 if (!handleParamError(asyncResp->res, errorMessage->message,
771ba498310SKrzysztof Grobelny                                       arg))
772ba498310SKrzysztof Grobelny                 {
773ba498310SKrzysztof Grobelny                     return;
774ba498310SKrzysztof Grobelny                 }
775ba498310SKrzysztof Grobelny             }
776ba498310SKrzysztof Grobelny         }
777ba498310SKrzysztof Grobelny     }
778ba498310SKrzysztof Grobelny     if (!verifyCommonErrors(asyncResp->res, args.id, ec))
779ba498310SKrzysztof Grobelny     {
780ba498310SKrzysztof Grobelny         return;
781ba498310SKrzysztof Grobelny     }
782ba498310SKrzysztof Grobelny     messages::internalError(asyncResp->res);
783ba498310SKrzysztof Grobelny }
784ba498310SKrzysztof Grobelny 
7854dbb8aeaSWludzik, Jozef class AddReport
7864dbb8aeaSWludzik, Jozef {
7874dbb8aeaSWludzik, Jozef   public:
788891eaa7cSEd Tanous     AddReport(AddReportArgs&& argsIn,
7898a592810SEd Tanous               const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
790bd79bce8SPatrick Williams         asyncResp(asyncRespIn), args(std::move(argsIn))
7914dbb8aeaSWludzik, Jozef     {}
792479e899dSKrzysztof Grobelny 
7934dbb8aeaSWludzik, Jozef     ~AddReport()
7944dbb8aeaSWludzik, Jozef     {
795479e899dSKrzysztof Grobelny         boost::asio::post(crow::connections::systemBus->get_io_context(),
796479e899dSKrzysztof Grobelny                           std::bind_front(&performAddReport, asyncResp, args,
797479e899dSKrzysztof Grobelny                                           std::move(uriToDbus)));
798479e899dSKrzysztof Grobelny     }
799479e899dSKrzysztof Grobelny 
800479e899dSKrzysztof Grobelny     static void performAddReport(
801479e899dSKrzysztof Grobelny         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
802479e899dSKrzysztof Grobelny         const AddReportArgs& args,
803479e899dSKrzysztof Grobelny         const boost::container::flat_map<std::string, std::string>& uriToDbus)
804479e899dSKrzysztof Grobelny     {
8054dbb8aeaSWludzik, Jozef         if (asyncResp->res.result() != boost::beast::http::status::ok)
8064dbb8aeaSWludzik, Jozef         {
8074dbb8aeaSWludzik, Jozef             return;
8084dbb8aeaSWludzik, Jozef         }
8094dbb8aeaSWludzik, Jozef 
8104dbb8aeaSWludzik, Jozef         telemetry::ReadingParameters readingParams;
8114dbb8aeaSWludzik, Jozef         readingParams.reserve(args.metrics.size());
8124dbb8aeaSWludzik, Jozef 
813479e899dSKrzysztof Grobelny         for (const auto& metric : args.metrics)
8144dbb8aeaSWludzik, Jozef         {
815479e899dSKrzysztof Grobelny             std::vector<
816479e899dSKrzysztof Grobelny                 std::tuple<sdbusplus::message::object_path, std::string>>
817479e899dSKrzysztof Grobelny                 sensorParams;
818479e899dSKrzysztof Grobelny             sensorParams.reserve(metric.uris.size());
819479e899dSKrzysztof Grobelny 
820479e899dSKrzysztof Grobelny             for (size_t i = 0; i < metric.uris.size(); i++)
8214dbb8aeaSWludzik, Jozef             {
822479e899dSKrzysztof Grobelny                 const std::string& uri = metric.uris[i];
8234dbb8aeaSWludzik, Jozef                 auto el = uriToDbus.find(uri);
8244dbb8aeaSWludzik, Jozef                 if (el == uriToDbus.end())
8254dbb8aeaSWludzik, Jozef                 {
82662598e31SEd Tanous                     BMCWEB_LOG_ERROR(
82762598e31SEd Tanous                         "Failed to find DBus sensor corresponding to URI {}",
82862598e31SEd Tanous                         uri);
829bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
830bd79bce8SPatrick Williams                         asyncResp->res, uri,
831bd79bce8SPatrick Williams                         "MetricProperties/" + std::to_string(i));
8324dbb8aeaSWludzik, Jozef                     return;
8334dbb8aeaSWludzik, Jozef                 }
8344dbb8aeaSWludzik, Jozef 
8354dbb8aeaSWludzik, Jozef                 const std::string& dbusPath = el->second;
836479e899dSKrzysztof Grobelny                 sensorParams.emplace_back(dbusPath, uri);
8374dbb8aeaSWludzik, Jozef             }
838479e899dSKrzysztof Grobelny 
839479e899dSKrzysztof Grobelny             readingParams.emplace_back(
840479e899dSKrzysztof Grobelny                 std::move(sensorParams), metric.collectionFunction,
841479e899dSKrzysztof Grobelny                 metric.collectionTimeScope, metric.collectionDuration);
8424dbb8aeaSWludzik, Jozef         }
843*177612aaSEd Tanous         dbus::utility::async_method_call(
844*177612aaSEd Tanous             asyncResp,
845ba498310SKrzysztof Grobelny             [asyncResp, args](const boost::system::error_code& ec,
846ba498310SKrzysztof Grobelny                               const sdbusplus::message_t& msg,
847ba498310SKrzysztof Grobelny                               const std::string& /*arg1*/) {
848ba498310SKrzysztof Grobelny                 afterAddReport(asyncResp, args, ec, msg);
8494dbb8aeaSWludzik, Jozef             },
8504dbb8aeaSWludzik, Jozef             telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
8514dbb8aeaSWludzik, Jozef             "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
852479e899dSKrzysztof Grobelny             "TelemetryService/" + args.id, args.name, args.reportingType,
853479e899dSKrzysztof Grobelny             args.reportUpdates, args.appendLimit, args.reportActions,
854479e899dSKrzysztof Grobelny             args.interval, readingParams, args.metricReportDefinitionEnabled);
8554dbb8aeaSWludzik, Jozef     }
8564dbb8aeaSWludzik, Jozef 
857ecd6a3a2SEd Tanous     AddReport(const AddReport&) = delete;
858ecd6a3a2SEd Tanous     AddReport(AddReport&&) = delete;
859ecd6a3a2SEd Tanous     AddReport& operator=(const AddReport&) = delete;
860ecd6a3a2SEd Tanous     AddReport& operator=(AddReport&&) = delete;
861ecd6a3a2SEd Tanous 
862fe04d49cSNan Zhou     void insert(const std::map<std::string, std::string>& el)
8634dbb8aeaSWludzik, Jozef     {
8644dbb8aeaSWludzik, Jozef         uriToDbus.insert(el.begin(), el.end());
8654dbb8aeaSWludzik, Jozef     }
8664dbb8aeaSWludzik, Jozef 
8674dbb8aeaSWludzik, Jozef   private:
868ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
8694dbb8aeaSWludzik, Jozef     AddReportArgs args;
87047f2934cSEd Tanous     boost::container::flat_map<std::string, std::string> uriToDbus;
8714dbb8aeaSWludzik, Jozef };
8729e6c388aSLukasz Kazmierczak 
873ba498310SKrzysztof Grobelny inline std::optional<
874ba498310SKrzysztof Grobelny     std::vector<std::tuple<sdbusplus::message::object_path, std::string>>>
875ba498310SKrzysztof Grobelny     sensorPathToUri(
876ba498310SKrzysztof Grobelny         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
877ba498310SKrzysztof Grobelny         std::span<const std::string> uris,
878ba498310SKrzysztof Grobelny         const std::map<std::string, std::string>& metricPropertyToDbusPaths)
879ba498310SKrzysztof Grobelny {
880ba498310SKrzysztof Grobelny     std::vector<std::tuple<sdbusplus::message::object_path, std::string>>
881ba498310SKrzysztof Grobelny         result;
882ba498310SKrzysztof Grobelny 
883ba498310SKrzysztof Grobelny     for (const std::string& uri : uris)
884ba498310SKrzysztof Grobelny     {
885ba498310SKrzysztof Grobelny         auto it = metricPropertyToDbusPaths.find(uri);
886ba498310SKrzysztof Grobelny         if (it == metricPropertyToDbusPaths.end())
887ba498310SKrzysztof Grobelny         {
888ba498310SKrzysztof Grobelny             messages::propertyValueNotInList(asyncResp->res, uri,
889ba498310SKrzysztof Grobelny                                              "MetricProperties");
890ba498310SKrzysztof Grobelny             return {};
891ba498310SKrzysztof Grobelny         }
892ba498310SKrzysztof Grobelny         result.emplace_back(it->second, uri);
893ba498310SKrzysztof Grobelny     }
894ba498310SKrzysztof Grobelny 
895ba498310SKrzysztof Grobelny     return result;
896ba498310SKrzysztof Grobelny }
897ba498310SKrzysztof Grobelny 
898ba498310SKrzysztof Grobelny inline void afterSetReadingParams(
899ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
900ba498310SKrzysztof Grobelny     const std::string& reportId, const boost::system::error_code& ec,
901ba498310SKrzysztof Grobelny     const sdbusplus::message_t& msg)
902ba498310SKrzysztof Grobelny {
903ba498310SKrzysztof Grobelny     if (!ec)
904ba498310SKrzysztof Grobelny     {
905ba498310SKrzysztof Grobelny         messages::success(asyncResp->res);
906ba498310SKrzysztof Grobelny         return;
907ba498310SKrzysztof Grobelny     }
908ba498310SKrzysztof Grobelny     if (ec == boost::system::errc::invalid_argument)
909ba498310SKrzysztof Grobelny     {
910ba498310SKrzysztof Grobelny         const sd_bus_error* errorMessage = msg.get_error();
911ba498310SKrzysztof Grobelny         if (errorMessage != nullptr)
912ba498310SKrzysztof Grobelny         {
913ba498310SKrzysztof Grobelny             for (const auto& arg : {"Id", "ReadingParameters"})
914ba498310SKrzysztof Grobelny             {
915ba498310SKrzysztof Grobelny                 if (!handleParamError(asyncResp->res, errorMessage->message,
916ba498310SKrzysztof Grobelny                                       arg))
917ba498310SKrzysztof Grobelny                 {
918ba498310SKrzysztof Grobelny                     return;
919ba498310SKrzysztof Grobelny                 }
920ba498310SKrzysztof Grobelny             }
921ba498310SKrzysztof Grobelny         }
922ba498310SKrzysztof Grobelny     }
923ba498310SKrzysztof Grobelny     if (!verifyCommonErrors(asyncResp->res, reportId, ec))
924ba498310SKrzysztof Grobelny     {
925ba498310SKrzysztof Grobelny         return;
926ba498310SKrzysztof Grobelny     }
927ba498310SKrzysztof Grobelny     messages::internalError(asyncResp->res);
928ba498310SKrzysztof Grobelny }
929ba498310SKrzysztof Grobelny 
930ba498310SKrzysztof Grobelny inline void setReadingParams(
931ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
932ba498310SKrzysztof Grobelny     const std::string& reportId, ReadingParameters readingParams,
933ba498310SKrzysztof Grobelny     const std::vector<std::vector<std::string>>& readingParamsUris,
934ba498310SKrzysztof Grobelny     const std::map<std::string, std::string>& metricPropertyToDbusPaths)
935ba498310SKrzysztof Grobelny {
936ba498310SKrzysztof Grobelny     if (asyncResp->res.result() != boost::beast::http::status::ok)
937ba498310SKrzysztof Grobelny     {
938ba498310SKrzysztof Grobelny         return;
939ba498310SKrzysztof Grobelny     }
940ba498310SKrzysztof Grobelny 
941ba498310SKrzysztof Grobelny     for (size_t index = 0; index < readingParamsUris.size(); ++index)
942ba498310SKrzysztof Grobelny     {
943ba498310SKrzysztof Grobelny         std::span<const std::string> newUris = readingParamsUris[index];
944ba498310SKrzysztof Grobelny 
945ba498310SKrzysztof Grobelny         const std::optional<std::vector<
946ba498310SKrzysztof Grobelny             std::tuple<sdbusplus::message::object_path, std::string>>>
947ba498310SKrzysztof Grobelny             readingParam =
948ba498310SKrzysztof Grobelny                 sensorPathToUri(asyncResp, newUris, metricPropertyToDbusPaths);
949ba498310SKrzysztof Grobelny 
950ba498310SKrzysztof Grobelny         if (!readingParam)
951ba498310SKrzysztof Grobelny         {
952ba498310SKrzysztof Grobelny             return;
953ba498310SKrzysztof Grobelny         }
954ba498310SKrzysztof Grobelny 
955ba498310SKrzysztof Grobelny         for (const std::tuple<sdbusplus::message::object_path, std::string>&
956ba498310SKrzysztof Grobelny                  value : *readingParam)
957ba498310SKrzysztof Grobelny         {
958ba498310SKrzysztof Grobelny             std::get<0>(readingParams[index]).emplace_back(value);
959ba498310SKrzysztof Grobelny         }
960ba498310SKrzysztof Grobelny     }
961ba498310SKrzysztof Grobelny 
962*177612aaSEd Tanous     dbus::utility::async_method_call(
963*177612aaSEd Tanous         asyncResp,
964ba498310SKrzysztof Grobelny         [asyncResp, reportId](const boost::system::error_code& ec,
965ba498310SKrzysztof Grobelny                               const sdbusplus::message_t& msg) {
966ba498310SKrzysztof Grobelny             afterSetReadingParams(asyncResp, reportId, ec, msg);
967ba498310SKrzysztof Grobelny         },
968ba498310SKrzysztof Grobelny         "xyz.openbmc_project.Telemetry", getDbusReportPath(reportId),
969ba498310SKrzysztof Grobelny         "org.freedesktop.DBus.Properties", "Set",
970ba498310SKrzysztof Grobelny         "xyz.openbmc_project.Telemetry.Report", "ReadingParameters",
971ba498310SKrzysztof Grobelny         dbus::utility::DbusVariantType{readingParams});
972ba498310SKrzysztof Grobelny }
973ba498310SKrzysztof Grobelny 
9749e6c388aSLukasz Kazmierczak class UpdateMetrics
9759e6c388aSLukasz Kazmierczak {
9769e6c388aSLukasz Kazmierczak   public:
9779e6c388aSLukasz Kazmierczak     UpdateMetrics(std::string_view idIn,
9789e6c388aSLukasz Kazmierczak                   const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
979bd79bce8SPatrick Williams         id(idIn), asyncResp(asyncRespIn)
9809e6c388aSLukasz Kazmierczak     {}
9819e6c388aSLukasz Kazmierczak 
9829e6c388aSLukasz Kazmierczak     ~UpdateMetrics()
9839e6c388aSLukasz Kazmierczak     {
984ba498310SKrzysztof Grobelny         boost::asio::post(
985ba498310SKrzysztof Grobelny             crow::connections::systemBus->get_io_context(),
986ba498310SKrzysztof Grobelny             std::bind_front(&setReadingParams, asyncResp, id,
987ba498310SKrzysztof Grobelny                             std::move(readingParams), readingParamsUris,
988ba498310SKrzysztof Grobelny                             metricPropertyToDbusPaths));
9899e6c388aSLukasz Kazmierczak     }
9909e6c388aSLukasz Kazmierczak 
9919e6c388aSLukasz Kazmierczak     UpdateMetrics(const UpdateMetrics&) = delete;
9929e6c388aSLukasz Kazmierczak     UpdateMetrics(UpdateMetrics&&) = delete;
9939e6c388aSLukasz Kazmierczak     UpdateMetrics& operator=(const UpdateMetrics&) = delete;
9949e6c388aSLukasz Kazmierczak     UpdateMetrics& operator=(UpdateMetrics&&) = delete;
9959e6c388aSLukasz Kazmierczak 
9969e6c388aSLukasz Kazmierczak     std::string id;
9979e6c388aSLukasz Kazmierczak     std::map<std::string, std::string> metricPropertyToDbusPaths;
9989e6c388aSLukasz Kazmierczak 
9999e6c388aSLukasz Kazmierczak     void insert(const std::map<std::string, std::string>&
10009e6c388aSLukasz Kazmierczak                     additionalMetricPropertyToDbusPaths)
10019e6c388aSLukasz Kazmierczak     {
10029e6c388aSLukasz Kazmierczak         metricPropertyToDbusPaths.insert(
10039e6c388aSLukasz Kazmierczak             additionalMetricPropertyToDbusPaths.begin(),
10049e6c388aSLukasz Kazmierczak             additionalMetricPropertyToDbusPaths.end());
10059e6c388aSLukasz Kazmierczak     }
10069e6c388aSLukasz Kazmierczak 
1007bd79bce8SPatrick Williams     void emplace(
1008bd79bce8SPatrick Williams         std::span<
1009bd79bce8SPatrick Williams             const std::tuple<sdbusplus::message::object_path, std::string>>
10109e6c388aSLukasz Kazmierczak             pathAndUri,
10119e6c388aSLukasz Kazmierczak         const AddReportArgs::MetricArgs& metricArgs)
10129e6c388aSLukasz Kazmierczak     {
10139e6c388aSLukasz Kazmierczak         readingParamsUris.emplace_back(metricArgs.uris);
10149e6c388aSLukasz Kazmierczak         readingParams.emplace_back(
10159e6c388aSLukasz Kazmierczak             std::vector(pathAndUri.begin(), pathAndUri.end()),
10169e6c388aSLukasz Kazmierczak             metricArgs.collectionFunction, metricArgs.collectionTimeScope,
10179e6c388aSLukasz Kazmierczak             metricArgs.collectionDuration);
10189e6c388aSLukasz Kazmierczak     }
10199e6c388aSLukasz Kazmierczak 
10209e6c388aSLukasz Kazmierczak   private:
10219e6c388aSLukasz Kazmierczak     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
10229e6c388aSLukasz Kazmierczak     std::vector<std::vector<std::string>> readingParamsUris;
102347f2934cSEd Tanous     ReadingParameters readingParams;
10249e6c388aSLukasz Kazmierczak };
10259e6c388aSLukasz Kazmierczak 
1026504af5a0SPatrick Williams inline void setReportEnabled(
1027504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
1028504af5a0SPatrick Williams     bool enabled)
10299e6c388aSLukasz Kazmierczak {
1030*177612aaSEd Tanous     dbus::utility::async_method_call(
1031*177612aaSEd Tanous         asyncResp,
10329e6c388aSLukasz Kazmierczak         [asyncResp, id = std::string(id)](const boost::system::error_code& ec) {
10339e6c388aSLukasz Kazmierczak             if (!verifyCommonErrors(asyncResp->res, id, ec))
10349e6c388aSLukasz Kazmierczak             {
10359e6c388aSLukasz Kazmierczak                 return;
10369e6c388aSLukasz Kazmierczak             }
10379e6c388aSLukasz Kazmierczak         },
10389e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
10399e6c388aSLukasz Kazmierczak         "org.freedesktop.DBus.Properties", "Set",
10409e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry.Report", "Enabled",
10419e6c388aSLukasz Kazmierczak         dbus::utility::DbusVariantType{enabled});
10429e6c388aSLukasz Kazmierczak }
10439e6c388aSLukasz Kazmierczak 
1044ba498310SKrzysztof Grobelny inline void afterSetReportingProperties(
1045ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
1046ba498310SKrzysztof Grobelny     const boost::system::error_code& ec, const sdbusplus::message_t& msg)
1047ba498310SKrzysztof Grobelny {
1048ba498310SKrzysztof Grobelny     if (!ec)
1049ba498310SKrzysztof Grobelny     {
1050ba498310SKrzysztof Grobelny         asyncResp->res.result(boost::beast::http::status::no_content);
1051ba498310SKrzysztof Grobelny         return;
1052ba498310SKrzysztof Grobelny     }
1053ba498310SKrzysztof Grobelny 
1054ba498310SKrzysztof Grobelny     if (ec == boost::system::errc::invalid_argument)
1055ba498310SKrzysztof Grobelny     {
1056ba498310SKrzysztof Grobelny         const sd_bus_error* errorMessage = msg.get_error();
1057ba498310SKrzysztof Grobelny         if (errorMessage != nullptr)
1058ba498310SKrzysztof Grobelny         {
1059ba498310SKrzysztof Grobelny             for (const auto& arg : {"Id", "ReportingType", "Interval"})
1060ba498310SKrzysztof Grobelny             {
1061ba498310SKrzysztof Grobelny                 if (!handleParamError(asyncResp->res, errorMessage->message,
1062ba498310SKrzysztof Grobelny                                       arg))
1063ba498310SKrzysztof Grobelny                 {
1064ba498310SKrzysztof Grobelny                     return;
1065ba498310SKrzysztof Grobelny                 }
1066ba498310SKrzysztof Grobelny             }
1067ba498310SKrzysztof Grobelny         }
1068ba498310SKrzysztof Grobelny     }
1069ba498310SKrzysztof Grobelny     if (!verifyCommonErrors(asyncResp->res, id, ec))
1070ba498310SKrzysztof Grobelny     {
1071ba498310SKrzysztof Grobelny         return;
1072ba498310SKrzysztof Grobelny     }
1073ba498310SKrzysztof Grobelny     messages::internalError(asyncResp->res);
1074ba498310SKrzysztof Grobelny }
1075ba498310SKrzysztof Grobelny 
10769e6c388aSLukasz Kazmierczak inline void setReportTypeAndInterval(
10779e6c388aSLukasz Kazmierczak     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
1078b4361d63SEd Tanous     const std::optional<std::string>& reportingType,
1079b4361d63SEd Tanous     const std::optional<std::string>& recurrenceIntervalStr)
10809e6c388aSLukasz Kazmierczak {
1081b4361d63SEd Tanous     std::string dbusReportingType;
1082b4361d63SEd Tanous     if (reportingType)
1083b4361d63SEd Tanous     {
1084b4361d63SEd Tanous         dbusReportingType = toDbusReportingType(*reportingType);
1085b4361d63SEd Tanous         if (dbusReportingType.empty())
1086b4361d63SEd Tanous         {
1087b4361d63SEd Tanous             messages::propertyValueNotInList(asyncResp->res, *reportingType,
1088b4361d63SEd Tanous                                              "MetricReportDefinitionType");
1089b4361d63SEd Tanous             return;
1090b4361d63SEd Tanous         }
1091b4361d63SEd Tanous     }
1092b4361d63SEd Tanous 
1093b4361d63SEd Tanous     uint64_t recurrenceInterval = std::numeric_limits<uint64_t>::max();
1094b4361d63SEd Tanous     if (recurrenceIntervalStr)
1095b4361d63SEd Tanous     {
1096b4361d63SEd Tanous         std::optional<std::chrono::milliseconds> durationNum =
1097b4361d63SEd Tanous             time_utils::fromDurationString(*recurrenceIntervalStr);
1098b4361d63SEd Tanous         if (!durationNum || durationNum->count() < 0)
1099b4361d63SEd Tanous         {
1100b4361d63SEd Tanous             messages::propertyValueIncorrect(
1101b4361d63SEd Tanous                 asyncResp->res, "RecurrenceInterval", *recurrenceIntervalStr);
1102b4361d63SEd Tanous             return;
1103b4361d63SEd Tanous         }
1104b4361d63SEd Tanous 
1105b4361d63SEd Tanous         recurrenceInterval = static_cast<uint64_t>(durationNum->count());
1106b4361d63SEd Tanous     }
1107b4361d63SEd Tanous 
1108*177612aaSEd Tanous     dbus::utility::async_method_call(
1109*177612aaSEd Tanous         asyncResp,
1110ba498310SKrzysztof Grobelny         [asyncResp, id = std::string(id)](const boost::system::error_code& ec,
1111ba498310SKrzysztof Grobelny                                           const sdbusplus::message_t& msg) {
1112ba498310SKrzysztof Grobelny             afterSetReportingProperties(asyncResp, id, ec, msg);
11139e6c388aSLukasz Kazmierczak         },
11149e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
11159e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry.Report", "SetReportingProperties",
1116b4361d63SEd Tanous         dbusReportingType, recurrenceInterval);
11179e6c388aSLukasz Kazmierczak }
11189e6c388aSLukasz Kazmierczak 
1119ba498310SKrzysztof Grobelny inline void afterSetReportUpdates(
1120ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
1121ba498310SKrzysztof Grobelny     const boost::system::error_code& ec, const sdbusplus::message_t& msg)
1122ba498310SKrzysztof Grobelny {
1123ba498310SKrzysztof Grobelny     if (!ec)
1124ba498310SKrzysztof Grobelny     {
1125ba498310SKrzysztof Grobelny         asyncResp->res.result(boost::beast::http::status::no_content);
1126ba498310SKrzysztof Grobelny         return;
1127ba498310SKrzysztof Grobelny     }
1128ba498310SKrzysztof Grobelny     if (ec == boost::system::errc::invalid_argument)
1129ba498310SKrzysztof Grobelny     {
1130ba498310SKrzysztof Grobelny         const sd_bus_error* errorMessage = msg.get_error();
1131ba498310SKrzysztof Grobelny         if (errorMessage != nullptr)
1132ba498310SKrzysztof Grobelny         {
1133ba498310SKrzysztof Grobelny             for (const auto& arg : {"Id", "ReportUpdates"})
1134ba498310SKrzysztof Grobelny             {
1135ba498310SKrzysztof Grobelny                 if (!handleParamError(asyncResp->res, errorMessage->message,
1136ba498310SKrzysztof Grobelny                                       arg))
1137ba498310SKrzysztof Grobelny                 {
1138ba498310SKrzysztof Grobelny                     return;
1139ba498310SKrzysztof Grobelny                 }
1140ba498310SKrzysztof Grobelny             }
1141ba498310SKrzysztof Grobelny         }
1142ba498310SKrzysztof Grobelny     }
1143ba498310SKrzysztof Grobelny     if (!verifyCommonErrors(asyncResp->res, id, ec))
1144ba498310SKrzysztof Grobelny     {
1145ba498310SKrzysztof Grobelny         return;
1146ba498310SKrzysztof Grobelny     }
1147ba498310SKrzysztof Grobelny }
1148ba498310SKrzysztof Grobelny 
1149504af5a0SPatrick Williams inline void setReportUpdates(
1150504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
1151504af5a0SPatrick Williams     const std::string& reportUpdates)
11529e6c388aSLukasz Kazmierczak {
1153b4361d63SEd Tanous     std::string dbusReportUpdates = toDbusReportUpdates(reportUpdates);
1154b4361d63SEd Tanous     if (dbusReportUpdates.empty())
1155b4361d63SEd Tanous     {
1156b4361d63SEd Tanous         messages::propertyValueNotInList(asyncResp->res, reportUpdates,
1157b4361d63SEd Tanous                                          "ReportUpdates");
1158b4361d63SEd Tanous         return;
1159b4361d63SEd Tanous     }
1160*177612aaSEd Tanous     dbus::utility::async_method_call(
1161*177612aaSEd Tanous         asyncResp,
1162ba498310SKrzysztof Grobelny         [asyncResp, id = std::string(id)](const boost::system::error_code& ec,
1163ba498310SKrzysztof Grobelny                                           const sdbusplus::message_t& msg) {
1164ba498310SKrzysztof Grobelny             afterSetReportUpdates(asyncResp, id, ec, msg);
11659e6c388aSLukasz Kazmierczak         },
11669e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
11679e6c388aSLukasz Kazmierczak         "org.freedesktop.DBus.Properties", "Set",
11689e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry.Report", "ReportUpdates",
1169ba498310SKrzysztof Grobelny         dbus::utility::DbusVariantType{dbusReportUpdates});
1170ba498310SKrzysztof Grobelny }
1171ba498310SKrzysztof Grobelny 
1172ba498310SKrzysztof Grobelny inline void afterSetReportActions(
1173ba498310SKrzysztof Grobelny     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
1174ba498310SKrzysztof Grobelny     const boost::system::error_code& ec, const sdbusplus::message_t& msg)
1175ba498310SKrzysztof Grobelny {
1176ba498310SKrzysztof Grobelny     if (ec == boost::system::errc::invalid_argument)
1177ba498310SKrzysztof Grobelny     {
1178ba498310SKrzysztof Grobelny         const sd_bus_error* errorMessage = msg.get_error();
1179ba498310SKrzysztof Grobelny         if (errorMessage != nullptr)
1180ba498310SKrzysztof Grobelny         {
1181ba498310SKrzysztof Grobelny             for (const auto& arg : {"Id", "ReportActions"})
1182ba498310SKrzysztof Grobelny             {
1183ba498310SKrzysztof Grobelny                 if (!handleParamError(asyncResp->res, errorMessage->message,
1184ba498310SKrzysztof Grobelny                                       arg))
1185ba498310SKrzysztof Grobelny                 {
1186ba498310SKrzysztof Grobelny                     return;
1187ba498310SKrzysztof Grobelny                 }
1188ba498310SKrzysztof Grobelny             }
1189ba498310SKrzysztof Grobelny         }
1190ba498310SKrzysztof Grobelny     }
1191ba498310SKrzysztof Grobelny 
1192ba498310SKrzysztof Grobelny     if (!verifyCommonErrors(asyncResp->res, id, ec))
1193ba498310SKrzysztof Grobelny     {
1194ba498310SKrzysztof Grobelny         return;
1195ba498310SKrzysztof Grobelny     }
1196ba498310SKrzysztof Grobelny 
1197ba498310SKrzysztof Grobelny     messages::internalError(asyncResp->res);
11989e6c388aSLukasz Kazmierczak }
11999e6c388aSLukasz Kazmierczak 
1200bd79bce8SPatrick Williams inline void setReportActions(
1201bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
1202b4361d63SEd Tanous     const std::vector<std::string>& reportActions)
12039e6c388aSLukasz Kazmierczak {
1204b4361d63SEd Tanous     std::vector<std::string> dbusReportActions;
1205b4361d63SEd Tanous     if (!toDbusReportActions(asyncResp->res, reportActions, dbusReportActions))
1206b4361d63SEd Tanous     {
1207b4361d63SEd Tanous         return;
1208b4361d63SEd Tanous     }
1209b4361d63SEd Tanous 
1210*177612aaSEd Tanous     dbus::utility::async_method_call(
1211*177612aaSEd Tanous         asyncResp,
1212ba498310SKrzysztof Grobelny         [asyncResp, id = std::string(id)](const boost::system::error_code& ec,
1213ba498310SKrzysztof Grobelny                                           const sdbusplus::message_t& msg) {
1214ba498310SKrzysztof Grobelny             afterSetReportActions(asyncResp, id, ec, msg);
12159e6c388aSLukasz Kazmierczak         },
12169e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
12179e6c388aSLukasz Kazmierczak         "org.freedesktop.DBus.Properties", "Set",
12189e6c388aSLukasz Kazmierczak         "xyz.openbmc_project.Telemetry.Report", "ReportActions",
12199e6c388aSLukasz Kazmierczak         dbus::utility::DbusVariantType{dbusReportActions});
12209e6c388aSLukasz Kazmierczak }
12219e6c388aSLukasz Kazmierczak 
1222bd79bce8SPatrick Williams inline void setReportMetrics(
1223bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
1224a64919e8SBoleslaw Ogonczyk Makowski     std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>&&
1225a64919e8SBoleslaw Ogonczyk Makowski         metrics)
12269e6c388aSLukasz Kazmierczak {
1227deae6a78SEd Tanous     dbus::utility::getAllProperties(
1228deae6a78SEd Tanous         telemetry::service, telemetry::getDbusReportPath(id),
1229deae6a78SEd Tanous         telemetry::reportInterface,
1230ba498310SKrzysztof Grobelny         [asyncResp, id = std::string(id), redfishMetrics = std::move(metrics)](
12319e6c388aSLukasz Kazmierczak             boost::system::error_code ec,
12329e6c388aSLukasz Kazmierczak             const dbus::utility::DBusPropertiesMap& properties) mutable {
1233ba498310SKrzysztof Grobelny             if (!verifyCommonErrors(asyncResp->res, id, ec))
12349e6c388aSLukasz Kazmierczak             {
12359e6c388aSLukasz Kazmierczak                 return;
12369e6c388aSLukasz Kazmierczak             }
12379e6c388aSLukasz Kazmierczak 
12389e6c388aSLukasz Kazmierczak             ReadingParameters readingParams;
12399e6c388aSLukasz Kazmierczak 
12409e6c388aSLukasz Kazmierczak             const bool success = sdbusplus::unpackPropertiesNoThrow(
1241bd79bce8SPatrick Williams                 dbus_utils::UnpackErrorPrinter(), properties,
1242bd79bce8SPatrick Williams                 "ReadingParameters", readingParams);
12439e6c388aSLukasz Kazmierczak 
12449e6c388aSLukasz Kazmierczak             if (!success)
12459e6c388aSLukasz Kazmierczak             {
12469e6c388aSLukasz Kazmierczak                 messages::internalError(asyncResp->res);
12479e6c388aSLukasz Kazmierczak                 return;
12489e6c388aSLukasz Kazmierczak             }
12499e6c388aSLukasz Kazmierczak 
1250bd79bce8SPatrick Williams             auto updateMetricsReq =
1251bd79bce8SPatrick Williams                 std::make_shared<UpdateMetrics>(id, asyncResp);
12529e6c388aSLukasz Kazmierczak 
12539e6c388aSLukasz Kazmierczak             boost::container::flat_set<std::pair<std::string, std::string>>
12549e6c388aSLukasz Kazmierczak                 chassisSensors;
12559e6c388aSLukasz Kazmierczak 
12569e6c388aSLukasz Kazmierczak             size_t index = 0;
1257a64919e8SBoleslaw Ogonczyk Makowski             for (std::variant<nlohmann::json::object_t, std::nullptr_t>&
1258a64919e8SBoleslaw Ogonczyk Makowski                      metricVariant : redfishMetrics)
12599e6c388aSLukasz Kazmierczak             {
1260a64919e8SBoleslaw Ogonczyk Makowski                 nlohmann::json::object_t* metric =
1261a64919e8SBoleslaw Ogonczyk Makowski                     std::get_if<nlohmann::json::object_t>(&metricVariant);
1262a64919e8SBoleslaw Ogonczyk Makowski                 if (metric == nullptr)
1263a64919e8SBoleslaw Ogonczyk Makowski                 {
1264a64919e8SBoleslaw Ogonczyk Makowski                     index++;
1265a64919e8SBoleslaw Ogonczyk Makowski                     continue;
1266a64919e8SBoleslaw Ogonczyk Makowski                 }
1267a64919e8SBoleslaw Ogonczyk Makowski 
12689e6c388aSLukasz Kazmierczak                 AddReportArgs::MetricArgs metricArgs;
12699e6c388aSLukasz Kazmierczak                 std::vector<
12709e6c388aSLukasz Kazmierczak                     std::tuple<sdbusplus::message::object_path, std::string>>
12719e6c388aSLukasz Kazmierczak                     pathAndUri;
12729e6c388aSLukasz Kazmierczak 
12739e6c388aSLukasz Kazmierczak                 if (index < readingParams.size())
12749e6c388aSLukasz Kazmierczak                 {
12759e6c388aSLukasz Kazmierczak                     const ReadingParameters::value_type& existing =
12769e6c388aSLukasz Kazmierczak                         readingParams[index];
12779e6c388aSLukasz Kazmierczak 
1278dac07cadSBoleslaw Ogonczyk Makowski                     if (metric->empty())
1279dac07cadSBoleslaw Ogonczyk Makowski                     {
12809e6c388aSLukasz Kazmierczak                         pathAndUri = std::get<0>(existing);
1281dac07cadSBoleslaw Ogonczyk Makowski                     }
12829e6c388aSLukasz Kazmierczak                     metricArgs.collectionFunction = std::get<1>(existing);
12839e6c388aSLukasz Kazmierczak                     metricArgs.collectionTimeScope = std::get<2>(existing);
12849e6c388aSLukasz Kazmierczak                     metricArgs.collectionDuration = std::get<3>(existing);
12859e6c388aSLukasz Kazmierczak                 }
12869e6c388aSLukasz Kazmierczak 
1287a64919e8SBoleslaw Ogonczyk Makowski                 if (!getUserMetric(asyncResp->res, *metric, metricArgs))
12889e6c388aSLukasz Kazmierczak                 {
12899e6c388aSLukasz Kazmierczak                     return;
12909e6c388aSLukasz Kazmierczak                 }
12919e6c388aSLukasz Kazmierczak 
12929e6c388aSLukasz Kazmierczak                 std::optional<IncorrectMetricUri> error =
12939e6c388aSLukasz Kazmierczak                     getChassisSensorNode(metricArgs.uris, chassisSensors);
12949e6c388aSLukasz Kazmierczak 
12959e6c388aSLukasz Kazmierczak                 if (error)
12969e6c388aSLukasz Kazmierczak                 {
12979e6c388aSLukasz Kazmierczak                     messages::propertyValueIncorrect(
12989e6c388aSLukasz Kazmierczak                         asyncResp->res, error->uri,
12999e6c388aSLukasz Kazmierczak                         "MetricProperties/" + std::to_string(error->index));
13009e6c388aSLukasz Kazmierczak                     return;
13019e6c388aSLukasz Kazmierczak                 }
13029e6c388aSLukasz Kazmierczak 
13039e6c388aSLukasz Kazmierczak                 updateMetricsReq->emplace(pathAndUri, metricArgs);
13049e6c388aSLukasz Kazmierczak                 index++;
13059e6c388aSLukasz Kazmierczak             }
13069e6c388aSLukasz Kazmierczak 
13079e6c388aSLukasz Kazmierczak             for (const auto& [chassis, sensorType] : chassisSensors)
13089e6c388aSLukasz Kazmierczak             {
13099e6c388aSLukasz Kazmierczak                 retrieveUriToDbusMap(
13109e6c388aSLukasz Kazmierczak                     chassis, sensorType,
13119e6c388aSLukasz Kazmierczak                     [asyncResp, updateMetricsReq](
13129e6c388aSLukasz Kazmierczak                         const boost::beast::http::status status,
13139e6c388aSLukasz Kazmierczak                         const std::map<std::string, std::string>& uriToDbus) {
13149e6c388aSLukasz Kazmierczak                         if (status != boost::beast::http::status::ok)
13159e6c388aSLukasz Kazmierczak                         {
13169e6c388aSLukasz Kazmierczak                             BMCWEB_LOG_ERROR(
13179e6c388aSLukasz Kazmierczak                                 "Failed to retrieve URI to dbus sensors map with err {}",
13189e6c388aSLukasz Kazmierczak                                 static_cast<unsigned>(status));
13199e6c388aSLukasz Kazmierczak                             return;
13209e6c388aSLukasz Kazmierczak                         }
13219e6c388aSLukasz Kazmierczak                         updateMetricsReq->insert(uriToDbus);
13229e6c388aSLukasz Kazmierczak                     });
13239e6c388aSLukasz Kazmierczak             }
13249e6c388aSLukasz Kazmierczak         });
13259e6c388aSLukasz Kazmierczak }
1326081ebf06SWludzik, Jozef 
13274220be3bSEd Tanous inline void handleMetricReportDefinitionCollectionHead(
13284220be3bSEd Tanous     App& app, const crow::Request& req,
13294220be3bSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
13304220be3bSEd Tanous {
13314220be3bSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
13324220be3bSEd Tanous     {
13334220be3bSEd Tanous         return;
13344220be3bSEd Tanous     }
13354220be3bSEd Tanous     asyncResp->res.addHeader(
13364220be3bSEd Tanous         boost::beast::http::field::link,
13374220be3bSEd Tanous         "</redfish/v1/JsonSchemas/MetricReportDefinitionCollection/MetricReportDefinitionCollection.json>; rel=describedby");
13384220be3bSEd Tanous }
13394220be3bSEd Tanous 
13404220be3bSEd Tanous inline void handleMetricReportDefinitionCollectionGet(
1341fc0edbe3SEd Tanous     App& app, const crow::Request& req,
1342fc0edbe3SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1343fc0edbe3SEd Tanous {
1344fc0edbe3SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1345fc0edbe3SEd Tanous     {
1346fc0edbe3SEd Tanous         return;
1347fc0edbe3SEd Tanous     }
13489e6c388aSLukasz Kazmierczak     asyncResp->res.addHeader(
13499e6c388aSLukasz Kazmierczak         boost::beast::http::field::link,
13509e6c388aSLukasz Kazmierczak         "</redfish/v1/JsonSchemas/MetricReportDefinition/MetricReportDefinition.json>; rel=describedby");
1351fc0edbe3SEd Tanous 
1352fc0edbe3SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
1353fc0edbe3SEd Tanous         "#MetricReportDefinitionCollection."
1354fc0edbe3SEd Tanous         "MetricReportDefinitionCollection";
1355fc0edbe3SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
1356fc0edbe3SEd Tanous         "/redfish/v1/TelemetryService/MetricReportDefinitions";
1357fc0edbe3SEd Tanous     asyncResp->res.jsonValue["Name"] = "Metric Definition Collection";
1358fc0edbe3SEd Tanous     constexpr std::array<std::string_view, 1> interfaces{
1359fc0edbe3SEd Tanous         telemetry::reportInterface};
1360fc0edbe3SEd Tanous     collection_util::getCollectionMembers(
1361fc0edbe3SEd Tanous         asyncResp,
1362fc0edbe3SEd Tanous         boost::urls::url(
1363fc0edbe3SEd Tanous             "/redfish/v1/TelemetryService/MetricReportDefinitions"),
1364fc0edbe3SEd Tanous         interfaces, "/xyz/openbmc_project/Telemetry/Reports/TelemetryService");
1365fc0edbe3SEd Tanous }
1366fc0edbe3SEd Tanous 
1367bd79bce8SPatrick Williams inline void handleReportPatch(
1368bd79bce8SPatrick Williams     App& app, const crow::Request& req,
1369bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id)
13709e6c388aSLukasz Kazmierczak {
13719e6c388aSLukasz Kazmierczak     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
13729e6c388aSLukasz Kazmierczak     {
13739e6c388aSLukasz Kazmierczak         return;
13749e6c388aSLukasz Kazmierczak     }
13759e6c388aSLukasz Kazmierczak 
13769e6c388aSLukasz Kazmierczak     std::optional<std::string> reportingTypeStr;
13779e6c388aSLukasz Kazmierczak     std::optional<std::string> reportUpdatesStr;
13789e6c388aSLukasz Kazmierczak     std::optional<bool> metricReportDefinitionEnabled;
1379a64919e8SBoleslaw Ogonczyk Makowski     std::optional<
1380a64919e8SBoleslaw Ogonczyk Makowski         std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>
1381a64919e8SBoleslaw Ogonczyk Makowski         metrics;
13829e6c388aSLukasz Kazmierczak     std::optional<std::vector<std::string>> reportActionsStr;
1383b14f357fSEd Tanous     std::optional<std::string> scheduleDurationStr;
13849e6c388aSLukasz Kazmierczak 
1385afc474aeSMyung Bae     if (!json_util::readJsonPatch(                                          //
1386afc474aeSMyung Bae             req, asyncResp->res,                                            //
1387afc474aeSMyung Bae             "MetricReportDefinitionEnabled", metricReportDefinitionEnabled, //
1388afc474aeSMyung Bae             "MetricReportDefinitionType", reportingTypeStr,                 //
1389afc474aeSMyung Bae             "Metrics", metrics,                                             //
1390afc474aeSMyung Bae             "ReportActions", reportActionsStr,                              //
1391afc474aeSMyung Bae             "ReportUpdates", reportUpdatesStr,                              //
1392afc474aeSMyung Bae             "Schedule/RecurrenceInterval", scheduleDurationStr              //
1393afc474aeSMyung Bae             ))
13949e6c388aSLukasz Kazmierczak     {
13959e6c388aSLukasz Kazmierczak         return;
13969e6c388aSLukasz Kazmierczak     }
13979e6c388aSLukasz Kazmierczak 
13989e6c388aSLukasz Kazmierczak     if (metricReportDefinitionEnabled)
13999e6c388aSLukasz Kazmierczak     {
14009e6c388aSLukasz Kazmierczak         setReportEnabled(asyncResp, id, *metricReportDefinitionEnabled);
14019e6c388aSLukasz Kazmierczak     }
14029e6c388aSLukasz Kazmierczak 
14039e6c388aSLukasz Kazmierczak     if (reportUpdatesStr)
14049e6c388aSLukasz Kazmierczak     {
1405b4361d63SEd Tanous         setReportUpdates(asyncResp, id, *reportUpdatesStr);
14069e6c388aSLukasz Kazmierczak     }
14079e6c388aSLukasz Kazmierczak 
14089e6c388aSLukasz Kazmierczak     if (reportActionsStr)
14099e6c388aSLukasz Kazmierczak     {
1410b4361d63SEd Tanous         setReportActions(asyncResp, id, *reportActionsStr);
14119e6c388aSLukasz Kazmierczak     }
14129e6c388aSLukasz Kazmierczak 
1413b14f357fSEd Tanous     if (reportingTypeStr || scheduleDurationStr)
14149e6c388aSLukasz Kazmierczak     {
1415b4361d63SEd Tanous         setReportTypeAndInterval(asyncResp, id, reportingTypeStr,
1416b4361d63SEd Tanous                                  scheduleDurationStr);
14179e6c388aSLukasz Kazmierczak     }
14189e6c388aSLukasz Kazmierczak 
14199e6c388aSLukasz Kazmierczak     if (metrics)
14209e6c388aSLukasz Kazmierczak     {
1421ba498310SKrzysztof Grobelny         setReportMetrics(asyncResp, id, std::move(*metrics));
14229e6c388aSLukasz Kazmierczak     }
14239e6c388aSLukasz Kazmierczak }
14249e6c388aSLukasz Kazmierczak 
1425bd79bce8SPatrick Williams inline void handleReportDelete(
1426bd79bce8SPatrick Williams     App& app, const crow::Request& req,
1427bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id)
14289e6c388aSLukasz Kazmierczak {
14299e6c388aSLukasz Kazmierczak     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
14309e6c388aSLukasz Kazmierczak     {
14319e6c388aSLukasz Kazmierczak         return;
14329e6c388aSLukasz Kazmierczak     }
14339e6c388aSLukasz Kazmierczak 
14349e6c388aSLukasz Kazmierczak     const std::string reportPath = getDbusReportPath(id);
14359e6c388aSLukasz Kazmierczak 
1436*177612aaSEd Tanous     dbus::utility::async_method_call(
1437*177612aaSEd Tanous         asyncResp,
14389e6c388aSLukasz Kazmierczak         [asyncResp,
14399e6c388aSLukasz Kazmierczak          reportId = std::string(id)](const boost::system::error_code& ec) {
14409e6c388aSLukasz Kazmierczak             if (!verifyCommonErrors(asyncResp->res, reportId, ec))
14419e6c388aSLukasz Kazmierczak             {
14429e6c388aSLukasz Kazmierczak                 return;
14439e6c388aSLukasz Kazmierczak             }
14449e6c388aSLukasz Kazmierczak             asyncResp->res.result(boost::beast::http::status::no_content);
14459e6c388aSLukasz Kazmierczak         },
14469e6c388aSLukasz Kazmierczak         service, reportPath, "xyz.openbmc_project.Object.Delete", "Delete");
14479e6c388aSLukasz Kazmierczak }
14489e6c388aSLukasz Kazmierczak } // namespace telemetry
14499e6c388aSLukasz Kazmierczak 
145095bdb5f0SEd Tanous inline void afterRetrieveUriToDbusMap(
145195bdb5f0SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
145295bdb5f0SEd Tanous     const std::shared_ptr<telemetry::AddReport>& addReportReq,
145395bdb5f0SEd Tanous     const boost::beast::http::status status,
145495bdb5f0SEd Tanous     const std::map<std::string, std::string>& uriToDbus)
145595bdb5f0SEd Tanous {
145695bdb5f0SEd Tanous     if (status != boost::beast::http::status::ok)
145795bdb5f0SEd Tanous     {
145895bdb5f0SEd Tanous         BMCWEB_LOG_ERROR(
145995bdb5f0SEd Tanous             "Failed to retrieve URI to dbus sensors map with err {}",
146095bdb5f0SEd Tanous             static_cast<unsigned>(status));
146195bdb5f0SEd Tanous         return;
146295bdb5f0SEd Tanous     }
146395bdb5f0SEd Tanous     addReportReq->insert(uriToDbus);
146495bdb5f0SEd Tanous }
146595bdb5f0SEd Tanous 
14669e6c388aSLukasz Kazmierczak inline void handleMetricReportDefinitionsPost(
14679e6c388aSLukasz Kazmierczak     App& app, const crow::Request& req,
14689e6c388aSLukasz Kazmierczak     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
14699e6c388aSLukasz Kazmierczak {
14709e6c388aSLukasz Kazmierczak     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
14719e6c388aSLukasz Kazmierczak     {
14729e6c388aSLukasz Kazmierczak         return;
14739e6c388aSLukasz Kazmierczak     }
14749e6c388aSLukasz Kazmierczak 
14759e6c388aSLukasz Kazmierczak     telemetry::AddReportArgs args;
14769e6c388aSLukasz Kazmierczak     if (!telemetry::getUserParameters(asyncResp->res, req, args))
14779e6c388aSLukasz Kazmierczak     {
14789e6c388aSLukasz Kazmierczak         return;
14799e6c388aSLukasz Kazmierczak     }
14809e6c388aSLukasz Kazmierczak 
14819e6c388aSLukasz Kazmierczak     boost::container::flat_set<std::pair<std::string, std::string>>
14829e6c388aSLukasz Kazmierczak         chassisSensors;
14839e6c388aSLukasz Kazmierczak     if (!telemetry::getChassisSensorNodeFromMetrics(asyncResp, args.metrics,
14849e6c388aSLukasz Kazmierczak                                                     chassisSensors))
14859e6c388aSLukasz Kazmierczak     {
14869e6c388aSLukasz Kazmierczak         return;
14879e6c388aSLukasz Kazmierczak     }
14889e6c388aSLukasz Kazmierczak 
1489bd79bce8SPatrick Williams     auto addReportReq =
1490bd79bce8SPatrick Williams         std::make_shared<telemetry::AddReport>(std::move(args), asyncResp);
14919e6c388aSLukasz Kazmierczak     for (const auto& [chassis, sensorType] : chassisSensors)
14929e6c388aSLukasz Kazmierczak     {
149395bdb5f0SEd Tanous         retrieveUriToDbusMap(chassis, sensorType,
149495bdb5f0SEd Tanous                              std::bind_front(afterRetrieveUriToDbusMap,
149595bdb5f0SEd Tanous                                              asyncResp, addReportReq));
14969e6c388aSLukasz Kazmierczak     }
14979e6c388aSLukasz Kazmierczak }
14989e6c388aSLukasz Kazmierczak 
1499504af5a0SPatrick Williams inline void handleMetricReportHead(
1500504af5a0SPatrick Williams     App& app, const crow::Request& req,
15014220be3bSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15024220be3bSEd Tanous     const std::string& /*id*/)
15034220be3bSEd Tanous {
15044220be3bSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
15054220be3bSEd Tanous     {
15064220be3bSEd Tanous         return;
15074220be3bSEd Tanous     }
15084220be3bSEd Tanous     asyncResp->res.addHeader(
15094220be3bSEd Tanous         boost::beast::http::field::link,
15104220be3bSEd Tanous         "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby");
15114220be3bSEd Tanous }
15124220be3bSEd Tanous 
1513bd79bce8SPatrick Williams inline void handleMetricReportGet(
1514bd79bce8SPatrick Williams     App& app, const crow::Request& req,
1515bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
151686a5ac98SEd Tanous {
151786a5ac98SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
151886a5ac98SEd Tanous     {
151986a5ac98SEd Tanous         return;
152086a5ac98SEd Tanous     }
15214220be3bSEd Tanous     asyncResp->res.addHeader(
15224220be3bSEd Tanous         boost::beast::http::field::link,
15234220be3bSEd Tanous         "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby");
152486a5ac98SEd Tanous 
1525deae6a78SEd Tanous     dbus::utility::getAllProperties(
1526deae6a78SEd Tanous         telemetry::service, telemetry::getDbusReportPath(id),
1527deae6a78SEd Tanous         telemetry::reportInterface,
152886a5ac98SEd Tanous         [asyncResp, id](const boost::system::error_code& ec,
152986a5ac98SEd Tanous                         const dbus::utility::DBusPropertiesMap& properties) {
15309e6c388aSLukasz Kazmierczak             if (!redfish::telemetry::verifyCommonErrors(asyncResp->res, id, ec))
153186a5ac98SEd Tanous             {
153286a5ac98SEd Tanous                 return;
153386a5ac98SEd Tanous             }
153486a5ac98SEd Tanous 
153586a5ac98SEd Tanous             telemetry::fillReportDefinition(asyncResp, id, properties);
153686a5ac98SEd Tanous         });
153786a5ac98SEd Tanous }
153886a5ac98SEd Tanous 
1539dd1c4a9cSSzymon Dompke inline void handleMetricReportDelete(
1540dd1c4a9cSSzymon Dompke     App& app, const crow::Request& req,
1541dd1c4a9cSSzymon Dompke     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1542dd1c4a9cSSzymon Dompke 
1543dd1c4a9cSSzymon Dompke {
1544dd1c4a9cSSzymon Dompke     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1545dd1c4a9cSSzymon Dompke     {
1546dd1c4a9cSSzymon Dompke         return;
1547dd1c4a9cSSzymon Dompke     }
1548dd1c4a9cSSzymon Dompke 
1549dd1c4a9cSSzymon Dompke     const std::string reportPath = telemetry::getDbusReportPath(id);
1550dd1c4a9cSSzymon Dompke 
1551*177612aaSEd Tanous     dbus::utility::async_method_call(
1552*177612aaSEd Tanous         asyncResp,
1553dd1c4a9cSSzymon Dompke         [asyncResp, id](const boost::system::error_code& ec) {
1554dd1c4a9cSSzymon Dompke             /*
1555dd1c4a9cSSzymon Dompke              * boost::system::errc and std::errc are missing value
1556dd1c4a9cSSzymon Dompke              * for EBADR error that is defined in Linux.
1557dd1c4a9cSSzymon Dompke              */
1558dd1c4a9cSSzymon Dompke             if (ec.value() == EBADR)
1559dd1c4a9cSSzymon Dompke             {
1560bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res,
1561bd79bce8SPatrick Williams                                            "MetricReportDefinition", id);
1562dd1c4a9cSSzymon Dompke                 return;
1563dd1c4a9cSSzymon Dompke             }
1564dd1c4a9cSSzymon Dompke 
1565dd1c4a9cSSzymon Dompke             if (ec)
1566dd1c4a9cSSzymon Dompke             {
156762598e31SEd Tanous                 BMCWEB_LOG_ERROR("respHandler DBus error {}", ec);
1568dd1c4a9cSSzymon Dompke                 messages::internalError(asyncResp->res);
1569dd1c4a9cSSzymon Dompke                 return;
1570dd1c4a9cSSzymon Dompke             }
1571dd1c4a9cSSzymon Dompke 
1572dd1c4a9cSSzymon Dompke             asyncResp->res.result(boost::beast::http::status::no_content);
1573dd1c4a9cSSzymon Dompke         },
1574dd1c4a9cSSzymon Dompke         telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete",
1575dd1c4a9cSSzymon Dompke         "Delete");
1576dd1c4a9cSSzymon Dompke }
1577dd1c4a9cSSzymon Dompke 
15787e860f15SJohn Edward Broadbent inline void requestRoutesMetricReportDefinitionCollection(App& app)
1579081ebf06SWludzik, Jozef {
15807e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
15814220be3bSEd Tanous         .privileges(redfish::privileges::headMetricReportDefinitionCollection)
15824220be3bSEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
15839e6c388aSLukasz Kazmierczak             telemetry::handleMetricReportDefinitionCollectionHead,
15849e6c388aSLukasz Kazmierczak             std::ref(app)));
15854220be3bSEd Tanous 
15864220be3bSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
1587ed398213SEd Tanous         .privileges(redfish::privileges::getMetricReportDefinitionCollection)
15884220be3bSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
15899e6c388aSLukasz Kazmierczak             telemetry::handleMetricReportDefinitionCollectionGet,
15909e6c388aSLukasz Kazmierczak             std::ref(app)));
15914dbb8aeaSWludzik, Jozef 
15927e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
1593ed398213SEd Tanous         .privileges(redfish::privileges::postMetricReportDefinitionCollection)
1594002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
15959e6c388aSLukasz Kazmierczak             std::bind_front(handleMetricReportDefinitionsPost, std::ref(app)));
1596081ebf06SWludzik, Jozef }
1597081ebf06SWludzik, Jozef 
15987e860f15SJohn Edward Broadbent inline void requestRoutesMetricReportDefinition(App& app)
1599081ebf06SWludzik, Jozef {
16007e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
16017e860f15SJohn Edward Broadbent                  "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
1602ed398213SEd Tanous         .privileges(redfish::privileges::getMetricReportDefinition)
16034220be3bSEd Tanous         .methods(boost::beast::http::verb::head)(
16044220be3bSEd Tanous             std::bind_front(handleMetricReportHead, std::ref(app)));
16054220be3bSEd Tanous 
16064220be3bSEd Tanous     BMCWEB_ROUTE(app,
16074220be3bSEd Tanous                  "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
16084220be3bSEd Tanous         .privileges(redfish::privileges::getMetricReportDefinition)
16097e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
161086a5ac98SEd Tanous             std::bind_front(handleMetricReportGet, std::ref(app)));
1611479e899dSKrzysztof Grobelny 
16127e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
16137e860f15SJohn Edward Broadbent                  "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
16149e6c388aSLukasz Kazmierczak         .privileges(redfish::privileges::deleteMetricReportDefinition)
16157e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
1616dd1c4a9cSSzymon Dompke             std::bind_front(handleMetricReportDelete, std::ref(app)));
16179e6c388aSLukasz Kazmierczak 
16189e6c388aSLukasz Kazmierczak     BMCWEB_ROUTE(app,
16199e6c388aSLukasz Kazmierczak                  "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
16209e6c388aSLukasz Kazmierczak         .privileges(redfish::privileges::patchMetricReportDefinition)
16219e6c388aSLukasz Kazmierczak         .methods(boost::beast::http::verb::patch)(
16229e6c388aSLukasz Kazmierczak             std::bind_front(telemetry::handleReportPatch, std::ref(app)));
16234dbb8aeaSWludzik, Jozef }
1624081ebf06SWludzik, Jozef } // namespace redfish
1625