1 #pragma once
2 
3 #include "node.hpp"
4 #include "utils/telemetry_utils.hpp"
5 #include "utils/time_utils.hpp"
6 
7 #include <tuple>
8 #include <variant>
9 
10 namespace redfish
11 {
12 
13 namespace telemetry
14 {
15 
16 using ReadingParameters =
17     std::vector<std::tuple<sdbusplus::message::object_path, std::string,
18                            std::string, std::string>>;
19 
20 inline void fillReportDefinition(
21     const std::shared_ptr<AsyncResp>& asyncResp, const std::string& id,
22     const std::vector<
23         std::pair<std::string, std::variant<std::string, bool, uint64_t,
24                                             ReadingParameters>>>& ret)
25 {
26     asyncResp->res.jsonValue["@odata.type"] =
27         "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
28     asyncResp->res.jsonValue["@odata.id"] =
29         telemetry::metricReportDefinitionUri + id;
30     asyncResp->res.jsonValue["Id"] = id;
31     asyncResp->res.jsonValue["Name"] = id;
32     asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
33         telemetry::metricReportUri + id;
34     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
35     asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
36 
37     const bool* emitsReadingsUpdate = nullptr;
38     const bool* logToMetricReportsCollection = nullptr;
39     const ReadingParameters* readingParams = nullptr;
40     const std::string* reportingType = nullptr;
41     const uint64_t* interval = nullptr;
42     for (const auto& [key, var] : ret)
43     {
44         if (key == "EmitsReadingsUpdate")
45         {
46             emitsReadingsUpdate = std::get_if<bool>(&var);
47         }
48         else if (key == "LogToMetricReportsCollection")
49         {
50             logToMetricReportsCollection = std::get_if<bool>(&var);
51         }
52         else if (key == "ReadingParameters")
53         {
54             readingParams = std::get_if<ReadingParameters>(&var);
55         }
56         else if (key == "ReportingType")
57         {
58             reportingType = std::get_if<std::string>(&var);
59         }
60         else if (key == "Interval")
61         {
62             interval = std::get_if<uint64_t>(&var);
63         }
64     }
65     if (!emitsReadingsUpdate || !logToMetricReportsCollection ||
66         !readingParams || !reportingType || !interval)
67     {
68         BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
69         messages::internalError(asyncResp->res);
70         return;
71     }
72 
73     std::vector<std::string> redfishReportActions;
74     redfishReportActions.reserve(2);
75     if (*emitsReadingsUpdate)
76     {
77         redfishReportActions.emplace_back("RedfishEvent");
78     }
79     if (*logToMetricReportsCollection)
80     {
81         redfishReportActions.emplace_back("LogToMetricReportsCollection");
82     }
83 
84     nlohmann::json metrics = nlohmann::json::array();
85     for (auto& [sensorPath, operationType, id, metadata] : *readingParams)
86     {
87         metrics.push_back({
88             {"MetricId", id},
89             {"MetricProperties", {metadata}},
90         });
91     }
92     asyncResp->res.jsonValue["Metrics"] = metrics;
93     asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType;
94     asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
95     asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
96         time_utils::toDurationString(std::chrono::milliseconds(*interval));
97 }
98 } // namespace telemetry
99 
100 class MetricReportDefinitionCollection : public Node
101 {
102   public:
103     MetricReportDefinitionCollection(App& app) :
104         Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
105     {
106         entityPrivileges = {
107             {boost::beast::http::verb::get, {{"Login"}}},
108             {boost::beast::http::verb::head, {{"Login"}}},
109             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
110             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
111             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
112             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
113     }
114 
115   private:
116     void doGet(crow::Response& res, const crow::Request&,
117                const std::vector<std::string>&) override
118     {
119         res.jsonValue["@odata.type"] = "#MetricReportDefinitionCollection."
120                                        "MetricReportDefinitionCollection";
121         res.jsonValue["@odata.id"] =
122             "/redfish/v1/TelemetryService/MetricReportDefinitions";
123         res.jsonValue["Name"] = "Metric Definition Collection";
124 
125         auto asyncResp = std::make_shared<AsyncResp>(res);
126         telemetry::getReportCollection(asyncResp,
127                                        telemetry::metricReportDefinitionUri);
128     }
129 };
130 
131 class MetricReportDefinition : public Node
132 {
133   public:
134     MetricReportDefinition(App& app) :
135         Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/",
136              std::string())
137     {
138         entityPrivileges = {
139             {boost::beast::http::verb::get, {{"Login"}}},
140             {boost::beast::http::verb::head, {{"Login"}}},
141             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
142             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
143             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
144             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
145     }
146 
147   private:
148     void doGet(crow::Response& res, const crow::Request&,
149                const std::vector<std::string>& params) override
150     {
151         auto asyncResp = std::make_shared<AsyncResp>(res);
152 
153         if (params.size() != 1)
154         {
155             messages::internalError(asyncResp->res);
156             return;
157         }
158 
159         const std::string& id = params[0];
160         crow::connections::systemBus->async_method_call(
161             [asyncResp,
162              id](const boost::system::error_code ec,
163                  const std::vector<std::pair<
164                      std::string, std::variant<std::string, bool, uint64_t,
165                                                telemetry::ReadingParameters>>>&
166                      ret) {
167                 if (ec.value() == EBADR ||
168                     ec == boost::system::errc::host_unreachable)
169                 {
170                     messages::resourceNotFound(asyncResp->res,
171                                                "MetricReportDefinition", id);
172                     return;
173                 }
174                 if (ec)
175                 {
176                     BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
177                     messages::internalError(asyncResp->res);
178                     return;
179                 }
180 
181                 telemetry::fillReportDefinition(asyncResp, id, ret);
182             },
183             telemetry::service, telemetry::getDbusReportPath(id),
184             "org.freedesktop.DBus.Properties", "GetAll",
185             telemetry::reportInterface);
186     }
187 };
188 } // namespace redfish
189