blob: b2ddec7ad8dff8c007b5055903df8315287d2dcd [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
zhanghch055ae1f7f2021-03-08 19:04:35 +08003#pragma once
4
5#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08006#include "async_resp.hpp"
7#include "dbus_singleton.hpp"
George Liu6fe87512023-07-20 15:06:37 +08008#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "error_messages.hpp"
10#include "http_request.hpp"
11#include "logging.hpp"
zhanghch055ae1f7f2021-03-08 19:04:35 +080012#include "query.hpp"
13#include "registries/privilege_registry.hpp"
14#include "utils/chassis_utils.hpp"
George Liu6fe87512023-07-20 15:06:37 +080015#include "utils/json_utils.hpp"
16#include "utils/sensor_utils.hpp"
zhanghch055ae1f7f2021-03-08 19:04:35 +080017
Ed Tanousd7857202025-01-28 15:32:26 -080018#include <asm-generic/errno.h>
19
20#include <boost/beast/http/field.hpp>
21#include <boost/beast/http/verb.hpp>
George Liu6fe87512023-07-20 15:06:37 +080022#include <boost/system/error_code.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080023#include <boost/url/format.hpp>
24#include <nlohmann/json.hpp>
George Liu6fe87512023-07-20 15:06:37 +080025
26#include <array>
zhanghch055ae1f7f2021-03-08 19:04:35 +080027#include <functional>
28#include <memory>
29#include <optional>
30#include <string>
George Liu6fe87512023-07-20 15:06:37 +080031#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080032#include <utility>
zhanghch055ae1f7f2021-03-08 19:04:35 +080033
34namespace redfish
35{
George Liu6fe87512023-07-20 15:06:37 +080036inline void afterGetTemperatureValue(
37 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
38 const std::string& chassisId, const std::string& path,
39 const boost::system::error_code& ec,
40 const dbus::utility::DBusPropertiesMap& valuesDict)
41{
42 if (ec)
43 {
44 if (ec.value() != EBADR)
45 {
46 BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}",
47 ec.value());
48 messages::internalError(asyncResp->res);
49 }
50 return;
51 }
52
53 nlohmann::json item = nlohmann::json::object();
54
55 /* Don't return an error for a failure to fill in properties from any of
56 * the sensors in the list. Just skip it.
57 */
58 if (sensor_utils::objectExcerptToJson(
59 path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode,
60 "temperature", valuesDict, item))
61 {
62 nlohmann::json& temperatureReadings =
63 asyncResp->res.jsonValue["TemperatureReadingsCelsius"];
64 nlohmann::json::array_t* temperatureArray =
65 temperatureReadings.get_ptr<nlohmann::json::array_t*>();
66 if (temperatureArray == nullptr)
67 {
68 BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array");
69 messages::internalError(asyncResp->res);
70 return;
71 }
72
73 temperatureArray->emplace_back(std::move(item));
74 asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] =
75 temperatureArray->size();
76
77 json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri");
78 }
79}
80
81inline void handleTemperatureReadingsCelsius(
82 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
83 const std::string& chassisId, const boost::system::error_code& ec,
84 const sensor_utils::SensorServicePathList& sensorsServiceAndPath)
85{
86 if (ec)
87 {
88 if (ec.value() != EBADR)
89 {
90 BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}",
91 ec.value());
92 messages::internalError(asyncResp->res);
93 }
94 return;
95 }
96
97 asyncResp->res.jsonValue["TemperatureReadingsCelsius"] =
98 nlohmann::json::array_t();
99 asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0;
100
101 for (const auto& [service, sensorPath] : sensorsServiceAndPath)
102 {
Ed Tanousdeae6a72024-11-11 21:58:57 -0800103 dbus::utility::getAllProperties(
George Liu6fe87512023-07-20 15:06:37 +0800104 *crow::connections::systemBus, service, sensorPath,
105 "xyz.openbmc_project.Sensor.Value",
106 [asyncResp, chassisId,
107 sensorPath](const boost::system::error_code& ec1,
108 const dbus::utility::DBusPropertiesMap& properties) {
109 afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1,
110 properties);
111 });
112 }
113}
114
115inline void getTemperatureReadingsCelsius(
116 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
117 const std::string& validChassisPath, const std::string& chassisId)
118{
119 constexpr std::array<std::string_view, 1> interfaces = {
120 "xyz.openbmc_project.Sensor.Value"};
121
122 sensor_utils::getAllSensorObjects(
123 validChassisPath, "/xyz/openbmc_project/sensors/temperature",
124 interfaces, 1,
125 std::bind_front(handleTemperatureReadingsCelsius, asyncResp,
126 chassisId));
127}
128
zhanghch055ae1f7f2021-03-08 19:04:35 +0800129inline void
130 doThermalMetrics(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
131 const std::string& chassisId,
132 const std::optional<std::string>& validChassisPath)
133{
134 if (!validChassisPath)
135 {
136 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
137 return;
138 }
139
140 asyncResp->res.addHeader(
141 boost::beast::http::field::link,
142 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
143 asyncResp->res.jsonValue["@odata.type"] =
144 "#ThermalMetrics.v1_0_1.ThermalMetrics";
145 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
146 "/redfish/v1/Chassis/{}/ThermalSubsystem/ThermalMetrics", chassisId);
147 asyncResp->res.jsonValue["Id"] = "ThermalMetrics";
148 asyncResp->res.jsonValue["Name"] = "Thermal Metrics";
George Liu6fe87512023-07-20 15:06:37 +0800149
150 getTemperatureReadingsCelsius(asyncResp, *validChassisPath, chassisId);
zhanghch055ae1f7f2021-03-08 19:04:35 +0800151}
152
153inline void handleThermalMetricsHead(
154 App& app, const crow::Request& req,
155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
156 const std::string& chassisId)
157{
158 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
159 {
160 return;
161 }
162
163 redfish::chassis_utils::getValidChassisPath(
164 asyncResp, chassisId,
165 [asyncResp,
166 chassisId](const std::optional<std::string>& validChassisPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400167 if (!validChassisPath)
168 {
169 messages::resourceNotFound(asyncResp->res, "Chassis",
170 chassisId);
171 return;
172 }
173 asyncResp->res.addHeader(
174 boost::beast::http::field::link,
175 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
176 });
zhanghch055ae1f7f2021-03-08 19:04:35 +0800177}
178
179inline void
180 handleThermalMetricsGet(App& app, const crow::Request& req,
181 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
182 const std::string& chassisId)
183{
184 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
185 {
186 return;
187 }
188
189 redfish::chassis_utils::getValidChassisPath(
190 asyncResp, chassisId,
191 std::bind_front(doThermalMetrics, asyncResp, chassisId));
192}
193
194inline void requestRoutesThermalMetrics(App& app)
195{
196 BMCWEB_ROUTE(app,
197 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
198 .privileges(redfish::privileges::headThermalMetrics)
199 .methods(boost::beast::http::verb::head)(
200 std::bind_front(handleThermalMetricsHead, std::ref(app)));
201
202 BMCWEB_ROUTE(app,
203 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
204 .privileges(redfish::privileges::getThermalMetrics)
205 .methods(boost::beast::http::verb::get)(
206 std::bind_front(handleThermalMetricsGet, std::ref(app)));
207}
208} // namespace redfish