1 #pragma once
2
3 #include "app.hpp"
4 #include "dbus_utility.hpp"
5 #include "query.hpp"
6 #include "registries/privilege_registry.hpp"
7 #include "utils/chassis_utils.hpp"
8 #include "utils/json_utils.hpp"
9 #include "utils/sensor_utils.hpp"
10
11 #include <boost/system/error_code.hpp>
12
13 #include <array>
14 #include <functional>
15 #include <memory>
16 #include <optional>
17 #include <string>
18 #include <string_view>
19
20 namespace redfish
21 {
afterGetTemperatureValue(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & path,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & valuesDict)22 inline void afterGetTemperatureValue(
23 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24 const std::string& chassisId, const std::string& path,
25 const boost::system::error_code& ec,
26 const dbus::utility::DBusPropertiesMap& valuesDict)
27 {
28 if (ec)
29 {
30 if (ec.value() != EBADR)
31 {
32 BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}",
33 ec.value());
34 messages::internalError(asyncResp->res);
35 }
36 return;
37 }
38
39 nlohmann::json item = nlohmann::json::object();
40
41 /* Don't return an error for a failure to fill in properties from any of
42 * the sensors in the list. Just skip it.
43 */
44 if (sensor_utils::objectExcerptToJson(
45 path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode,
46 "temperature", valuesDict, item))
47 {
48 nlohmann::json& temperatureReadings =
49 asyncResp->res.jsonValue["TemperatureReadingsCelsius"];
50 nlohmann::json::array_t* temperatureArray =
51 temperatureReadings.get_ptr<nlohmann::json::array_t*>();
52 if (temperatureArray == nullptr)
53 {
54 BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array");
55 messages::internalError(asyncResp->res);
56 return;
57 }
58
59 temperatureArray->emplace_back(std::move(item));
60 asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] =
61 temperatureArray->size();
62
63 json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri");
64 }
65 }
66
handleTemperatureReadingsCelsius(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const sensor_utils::SensorServicePathList & sensorsServiceAndPath)67 inline void handleTemperatureReadingsCelsius(
68 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
69 const std::string& chassisId, const boost::system::error_code& ec,
70 const sensor_utils::SensorServicePathList& sensorsServiceAndPath)
71 {
72 if (ec)
73 {
74 if (ec.value() != EBADR)
75 {
76 BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}",
77 ec.value());
78 messages::internalError(asyncResp->res);
79 }
80 return;
81 }
82
83 asyncResp->res.jsonValue["TemperatureReadingsCelsius"] =
84 nlohmann::json::array_t();
85 asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0;
86
87 for (const auto& [service, sensorPath] : sensorsServiceAndPath)
88 {
89 dbus::utility::getAllProperties(
90 *crow::connections::systemBus, service, sensorPath,
91 "xyz.openbmc_project.Sensor.Value",
92 [asyncResp, chassisId,
93 sensorPath](const boost::system::error_code& ec1,
94 const dbus::utility::DBusPropertiesMap& properties) {
95 afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1,
96 properties);
97 });
98 }
99 }
100
getTemperatureReadingsCelsius(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & validChassisPath,const std::string & chassisId)101 inline void getTemperatureReadingsCelsius(
102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103 const std::string& validChassisPath, const std::string& chassisId)
104 {
105 constexpr std::array<std::string_view, 1> interfaces = {
106 "xyz.openbmc_project.Sensor.Value"};
107
108 sensor_utils::getAllSensorObjects(
109 validChassisPath, "/xyz/openbmc_project/sensors/temperature",
110 interfaces, 1,
111 std::bind_front(handleTemperatureReadingsCelsius, asyncResp,
112 chassisId));
113 }
114
115 inline void
doThermalMetrics(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::optional<std::string> & validChassisPath)116 doThermalMetrics(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
117 const std::string& chassisId,
118 const std::optional<std::string>& validChassisPath)
119 {
120 if (!validChassisPath)
121 {
122 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
123 return;
124 }
125
126 asyncResp->res.addHeader(
127 boost::beast::http::field::link,
128 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
129 asyncResp->res.jsonValue["@odata.type"] =
130 "#ThermalMetrics.v1_0_1.ThermalMetrics";
131 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
132 "/redfish/v1/Chassis/{}/ThermalSubsystem/ThermalMetrics", chassisId);
133 asyncResp->res.jsonValue["Id"] = "ThermalMetrics";
134 asyncResp->res.jsonValue["Name"] = "Thermal Metrics";
135
136 getTemperatureReadingsCelsius(asyncResp, *validChassisPath, chassisId);
137 }
138
handleThermalMetricsHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)139 inline void handleThermalMetricsHead(
140 App& app, const crow::Request& req,
141 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
142 const std::string& chassisId)
143 {
144 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
145 {
146 return;
147 }
148
149 redfish::chassis_utils::getValidChassisPath(
150 asyncResp, chassisId,
151 [asyncResp,
152 chassisId](const std::optional<std::string>& validChassisPath) {
153 if (!validChassisPath)
154 {
155 messages::resourceNotFound(asyncResp->res, "Chassis",
156 chassisId);
157 return;
158 }
159 asyncResp->res.addHeader(
160 boost::beast::http::field::link,
161 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
162 });
163 }
164
165 inline void
handleThermalMetricsGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)166 handleThermalMetricsGet(App& app, const crow::Request& req,
167 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
168 const std::string& chassisId)
169 {
170 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
171 {
172 return;
173 }
174
175 redfish::chassis_utils::getValidChassisPath(
176 asyncResp, chassisId,
177 std::bind_front(doThermalMetrics, asyncResp, chassisId));
178 }
179
requestRoutesThermalMetrics(App & app)180 inline void requestRoutesThermalMetrics(App& app)
181 {
182 BMCWEB_ROUTE(app,
183 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
184 .privileges(redfish::privileges::headThermalMetrics)
185 .methods(boost::beast::http::verb::head)(
186 std::bind_front(handleThermalMetricsHead, std::ref(app)));
187
188 BMCWEB_ROUTE(app,
189 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
190 .privileges(redfish::privileges::getThermalMetrics)
191 .methods(boost::beast::http::verb::get)(
192 std::bind_front(handleThermalMetricsGet, std::ref(app)));
193 }
194 } // namespace redfish
195