1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 35ae1f7f3Szhanghch05 #pragma once 45ae1f7f3Szhanghch05 55ae1f7f3Szhanghch05 #include "app.hpp" 66fe8751cSGeorge Liu #include "dbus_utility.hpp" 75ae1f7f3Szhanghch05 #include "query.hpp" 85ae1f7f3Szhanghch05 #include "registries/privilege_registry.hpp" 95ae1f7f3Szhanghch05 #include "utils/chassis_utils.hpp" 106fe8751cSGeorge Liu #include "utils/json_utils.hpp" 116fe8751cSGeorge Liu #include "utils/sensor_utils.hpp" 125ae1f7f3Szhanghch05 136fe8751cSGeorge Liu #include <boost/system/error_code.hpp> 146fe8751cSGeorge Liu 156fe8751cSGeorge Liu #include <array> 165ae1f7f3Szhanghch05 #include <functional> 175ae1f7f3Szhanghch05 #include <memory> 185ae1f7f3Szhanghch05 #include <optional> 195ae1f7f3Szhanghch05 #include <string> 206fe8751cSGeorge Liu #include <string_view> 215ae1f7f3Szhanghch05 225ae1f7f3Szhanghch05 namespace redfish 235ae1f7f3Szhanghch05 { 246fe8751cSGeorge Liu inline void afterGetTemperatureValue( 256fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 266fe8751cSGeorge Liu const std::string& chassisId, const std::string& path, 276fe8751cSGeorge Liu const boost::system::error_code& ec, 286fe8751cSGeorge Liu const dbus::utility::DBusPropertiesMap& valuesDict) 296fe8751cSGeorge Liu { 306fe8751cSGeorge Liu if (ec) 316fe8751cSGeorge Liu { 326fe8751cSGeorge Liu if (ec.value() != EBADR) 336fe8751cSGeorge Liu { 346fe8751cSGeorge Liu BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}", 356fe8751cSGeorge Liu ec.value()); 366fe8751cSGeorge Liu messages::internalError(asyncResp->res); 376fe8751cSGeorge Liu } 386fe8751cSGeorge Liu return; 396fe8751cSGeorge Liu } 406fe8751cSGeorge Liu 416fe8751cSGeorge Liu nlohmann::json item = nlohmann::json::object(); 426fe8751cSGeorge Liu 436fe8751cSGeorge Liu /* Don't return an error for a failure to fill in properties from any of 446fe8751cSGeorge Liu * the sensors in the list. Just skip it. 456fe8751cSGeorge Liu */ 466fe8751cSGeorge Liu if (sensor_utils::objectExcerptToJson( 476fe8751cSGeorge Liu path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode, 486fe8751cSGeorge Liu "temperature", valuesDict, item)) 496fe8751cSGeorge Liu { 506fe8751cSGeorge Liu nlohmann::json& temperatureReadings = 516fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius"]; 526fe8751cSGeorge Liu nlohmann::json::array_t* temperatureArray = 536fe8751cSGeorge Liu temperatureReadings.get_ptr<nlohmann::json::array_t*>(); 546fe8751cSGeorge Liu if (temperatureArray == nullptr) 556fe8751cSGeorge Liu { 566fe8751cSGeorge Liu BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array"); 576fe8751cSGeorge Liu messages::internalError(asyncResp->res); 586fe8751cSGeorge Liu return; 596fe8751cSGeorge Liu } 606fe8751cSGeorge Liu 616fe8751cSGeorge Liu temperatureArray->emplace_back(std::move(item)); 626fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 636fe8751cSGeorge Liu temperatureArray->size(); 646fe8751cSGeorge Liu 656fe8751cSGeorge Liu json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri"); 666fe8751cSGeorge Liu } 676fe8751cSGeorge Liu } 686fe8751cSGeorge Liu 696fe8751cSGeorge Liu inline void handleTemperatureReadingsCelsius( 706fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 716fe8751cSGeorge Liu const std::string& chassisId, const boost::system::error_code& ec, 726fe8751cSGeorge Liu const sensor_utils::SensorServicePathList& sensorsServiceAndPath) 736fe8751cSGeorge Liu { 746fe8751cSGeorge Liu if (ec) 756fe8751cSGeorge Liu { 766fe8751cSGeorge Liu if (ec.value() != EBADR) 776fe8751cSGeorge Liu { 786fe8751cSGeorge Liu BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}", 796fe8751cSGeorge Liu ec.value()); 806fe8751cSGeorge Liu messages::internalError(asyncResp->res); 816fe8751cSGeorge Liu } 826fe8751cSGeorge Liu return; 836fe8751cSGeorge Liu } 846fe8751cSGeorge Liu 856fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius"] = 866fe8751cSGeorge Liu nlohmann::json::array_t(); 876fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0; 886fe8751cSGeorge Liu 896fe8751cSGeorge Liu for (const auto& [service, sensorPath] : sensorsServiceAndPath) 906fe8751cSGeorge Liu { 91deae6a78SEd Tanous dbus::utility::getAllProperties( 926fe8751cSGeorge Liu *crow::connections::systemBus, service, sensorPath, 936fe8751cSGeorge Liu "xyz.openbmc_project.Sensor.Value", 946fe8751cSGeorge Liu [asyncResp, chassisId, 956fe8751cSGeorge Liu sensorPath](const boost::system::error_code& ec1, 966fe8751cSGeorge Liu const dbus::utility::DBusPropertiesMap& properties) { 976fe8751cSGeorge Liu afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1, 986fe8751cSGeorge Liu properties); 996fe8751cSGeorge Liu }); 1006fe8751cSGeorge Liu } 1016fe8751cSGeorge Liu } 1026fe8751cSGeorge Liu 1036fe8751cSGeorge Liu inline void getTemperatureReadingsCelsius( 1046fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1056fe8751cSGeorge Liu const std::string& validChassisPath, const std::string& chassisId) 1066fe8751cSGeorge Liu { 1076fe8751cSGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1086fe8751cSGeorge Liu "xyz.openbmc_project.Sensor.Value"}; 1096fe8751cSGeorge Liu 1106fe8751cSGeorge Liu sensor_utils::getAllSensorObjects( 1116fe8751cSGeorge Liu validChassisPath, "/xyz/openbmc_project/sensors/temperature", 1126fe8751cSGeorge Liu interfaces, 1, 1136fe8751cSGeorge Liu std::bind_front(handleTemperatureReadingsCelsius, asyncResp, 1146fe8751cSGeorge Liu chassisId)); 1156fe8751cSGeorge Liu } 1166fe8751cSGeorge Liu 1175ae1f7f3Szhanghch05 inline void 1185ae1f7f3Szhanghch05 doThermalMetrics(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1195ae1f7f3Szhanghch05 const std::string& chassisId, 1205ae1f7f3Szhanghch05 const std::optional<std::string>& validChassisPath) 1215ae1f7f3Szhanghch05 { 1225ae1f7f3Szhanghch05 if (!validChassisPath) 1235ae1f7f3Szhanghch05 { 1245ae1f7f3Szhanghch05 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 1255ae1f7f3Szhanghch05 return; 1265ae1f7f3Szhanghch05 } 1275ae1f7f3Szhanghch05 1285ae1f7f3Szhanghch05 asyncResp->res.addHeader( 1295ae1f7f3Szhanghch05 boost::beast::http::field::link, 1305ae1f7f3Szhanghch05 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby"); 1315ae1f7f3Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1325ae1f7f3Szhanghch05 "#ThermalMetrics.v1_0_1.ThermalMetrics"; 1335ae1f7f3Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1345ae1f7f3Szhanghch05 "/redfish/v1/Chassis/{}/ThermalSubsystem/ThermalMetrics", chassisId); 1355ae1f7f3Szhanghch05 asyncResp->res.jsonValue["Id"] = "ThermalMetrics"; 1365ae1f7f3Szhanghch05 asyncResp->res.jsonValue["Name"] = "Thermal Metrics"; 1376fe8751cSGeorge Liu 1386fe8751cSGeorge Liu getTemperatureReadingsCelsius(asyncResp, *validChassisPath, chassisId); 1395ae1f7f3Szhanghch05 } 1405ae1f7f3Szhanghch05 1415ae1f7f3Szhanghch05 inline void handleThermalMetricsHead( 1425ae1f7f3Szhanghch05 App& app, const crow::Request& req, 1435ae1f7f3Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1445ae1f7f3Szhanghch05 const std::string& chassisId) 1455ae1f7f3Szhanghch05 { 1465ae1f7f3Szhanghch05 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1475ae1f7f3Szhanghch05 { 1485ae1f7f3Szhanghch05 return; 1495ae1f7f3Szhanghch05 } 1505ae1f7f3Szhanghch05 1515ae1f7f3Szhanghch05 redfish::chassis_utils::getValidChassisPath( 1525ae1f7f3Szhanghch05 asyncResp, chassisId, 1535ae1f7f3Szhanghch05 [asyncResp, 1545ae1f7f3Szhanghch05 chassisId](const std::optional<std::string>& validChassisPath) { 1555ae1f7f3Szhanghch05 if (!validChassisPath) 1565ae1f7f3Szhanghch05 { 157bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 158bd79bce8SPatrick Williams chassisId); 1595ae1f7f3Szhanghch05 return; 1605ae1f7f3Szhanghch05 } 1615ae1f7f3Szhanghch05 asyncResp->res.addHeader( 1625ae1f7f3Szhanghch05 boost::beast::http::field::link, 1635ae1f7f3Szhanghch05 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby"); 1645ae1f7f3Szhanghch05 }); 1655ae1f7f3Szhanghch05 } 1665ae1f7f3Szhanghch05 1675ae1f7f3Szhanghch05 inline void 1685ae1f7f3Szhanghch05 handleThermalMetricsGet(App& app, const crow::Request& req, 1695ae1f7f3Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1705ae1f7f3Szhanghch05 const std::string& chassisId) 1715ae1f7f3Szhanghch05 { 1725ae1f7f3Szhanghch05 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1735ae1f7f3Szhanghch05 { 1745ae1f7f3Szhanghch05 return; 1755ae1f7f3Szhanghch05 } 1765ae1f7f3Szhanghch05 1775ae1f7f3Szhanghch05 redfish::chassis_utils::getValidChassisPath( 1785ae1f7f3Szhanghch05 asyncResp, chassisId, 1795ae1f7f3Szhanghch05 std::bind_front(doThermalMetrics, asyncResp, chassisId)); 1805ae1f7f3Szhanghch05 } 1815ae1f7f3Szhanghch05 1825ae1f7f3Szhanghch05 inline void requestRoutesThermalMetrics(App& app) 1835ae1f7f3Szhanghch05 { 1845ae1f7f3Szhanghch05 BMCWEB_ROUTE(app, 1855ae1f7f3Szhanghch05 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/") 1865ae1f7f3Szhanghch05 .privileges(redfish::privileges::headThermalMetrics) 1875ae1f7f3Szhanghch05 .methods(boost::beast::http::verb::head)( 1885ae1f7f3Szhanghch05 std::bind_front(handleThermalMetricsHead, std::ref(app))); 1895ae1f7f3Szhanghch05 1905ae1f7f3Szhanghch05 BMCWEB_ROUTE(app, 1915ae1f7f3Szhanghch05 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/") 1925ae1f7f3Szhanghch05 .privileges(redfish::privileges::getThermalMetrics) 1935ae1f7f3Szhanghch05 .methods(boost::beast::http::verb::get)( 1945ae1f7f3Szhanghch05 std::bind_front(handleThermalMetricsGet, std::ref(app))); 1955ae1f7f3Szhanghch05 } 1965ae1f7f3Szhanghch05 } // namespace redfish 197