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 { 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 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 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 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 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 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 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