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