140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 35ae1f7f3Szhanghch05 #pragma once 45ae1f7f3Szhanghch05 55ae1f7f3Szhanghch05 #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 7d7857201SEd Tanous #include "dbus_singleton.hpp" 86fe8751cSGeorge Liu #include "dbus_utility.hpp" 9d7857201SEd Tanous #include "error_messages.hpp" 10d7857201SEd Tanous #include "http_request.hpp" 11d7857201SEd Tanous #include "logging.hpp" 125ae1f7f3Szhanghch05 #include "query.hpp" 135ae1f7f3Szhanghch05 #include "registries/privilege_registry.hpp" 145ae1f7f3Szhanghch05 #include "utils/chassis_utils.hpp" 156fe8751cSGeorge Liu #include "utils/json_utils.hpp" 166fe8751cSGeorge Liu #include "utils/sensor_utils.hpp" 175ae1f7f3Szhanghch05 18d7857201SEd Tanous #include <asm-generic/errno.h> 19d7857201SEd Tanous 20d7857201SEd Tanous #include <boost/beast/http/field.hpp> 21d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 226fe8751cSGeorge Liu #include <boost/system/error_code.hpp> 23d7857201SEd Tanous #include <boost/url/format.hpp> 24d7857201SEd Tanous #include <nlohmann/json.hpp> 256fe8751cSGeorge Liu 266fe8751cSGeorge Liu #include <array> 275ae1f7f3Szhanghch05 #include <functional> 285ae1f7f3Szhanghch05 #include <memory> 295ae1f7f3Szhanghch05 #include <optional> 305ae1f7f3Szhanghch05 #include <string> 316fe8751cSGeorge Liu #include <string_view> 32d7857201SEd Tanous #include <utility> 335ae1f7f3Szhanghch05 345ae1f7f3Szhanghch05 namespace redfish 355ae1f7f3Szhanghch05 { 366fe8751cSGeorge Liu inline void afterGetTemperatureValue( 376fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 386fe8751cSGeorge Liu const std::string& chassisId, const std::string& path, 396fe8751cSGeorge Liu const boost::system::error_code& ec, 406fe8751cSGeorge Liu const dbus::utility::DBusPropertiesMap& valuesDict) 416fe8751cSGeorge Liu { 426fe8751cSGeorge Liu if (ec) 436fe8751cSGeorge Liu { 446fe8751cSGeorge Liu if (ec.value() != EBADR) 456fe8751cSGeorge Liu { 466fe8751cSGeorge Liu BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}", 476fe8751cSGeorge Liu ec.value()); 486fe8751cSGeorge Liu messages::internalError(asyncResp->res); 496fe8751cSGeorge Liu } 506fe8751cSGeorge Liu return; 516fe8751cSGeorge Liu } 526fe8751cSGeorge Liu 536fe8751cSGeorge Liu nlohmann::json item = nlohmann::json::object(); 546fe8751cSGeorge Liu 556fe8751cSGeorge Liu /* Don't return an error for a failure to fill in properties from any of 566fe8751cSGeorge Liu * the sensors in the list. Just skip it. 576fe8751cSGeorge Liu */ 586fe8751cSGeorge Liu if (sensor_utils::objectExcerptToJson( 596fe8751cSGeorge Liu path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode, 606fe8751cSGeorge Liu "temperature", valuesDict, item)) 616fe8751cSGeorge Liu { 626fe8751cSGeorge Liu nlohmann::json& temperatureReadings = 636fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius"]; 646fe8751cSGeorge Liu nlohmann::json::array_t* temperatureArray = 656fe8751cSGeorge Liu temperatureReadings.get_ptr<nlohmann::json::array_t*>(); 666fe8751cSGeorge Liu if (temperatureArray == nullptr) 676fe8751cSGeorge Liu { 686fe8751cSGeorge Liu BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array"); 696fe8751cSGeorge Liu messages::internalError(asyncResp->res); 706fe8751cSGeorge Liu return; 716fe8751cSGeorge Liu } 726fe8751cSGeorge Liu 736fe8751cSGeorge Liu temperatureArray->emplace_back(std::move(item)); 746fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 756fe8751cSGeorge Liu temperatureArray->size(); 766fe8751cSGeorge Liu 776fe8751cSGeorge Liu json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri"); 786fe8751cSGeorge Liu } 796fe8751cSGeorge Liu } 806fe8751cSGeorge Liu 816fe8751cSGeorge Liu inline void handleTemperatureReadingsCelsius( 826fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 836fe8751cSGeorge Liu const std::string& chassisId, const boost::system::error_code& ec, 846fe8751cSGeorge Liu const sensor_utils::SensorServicePathList& sensorsServiceAndPath) 856fe8751cSGeorge Liu { 866fe8751cSGeorge Liu if (ec) 876fe8751cSGeorge Liu { 886fe8751cSGeorge Liu if (ec.value() != EBADR) 896fe8751cSGeorge Liu { 906fe8751cSGeorge Liu BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}", 916fe8751cSGeorge Liu ec.value()); 926fe8751cSGeorge Liu messages::internalError(asyncResp->res); 936fe8751cSGeorge Liu } 946fe8751cSGeorge Liu return; 956fe8751cSGeorge Liu } 966fe8751cSGeorge Liu 976fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius"] = 986fe8751cSGeorge Liu nlohmann::json::array_t(); 996fe8751cSGeorge Liu asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0; 1006fe8751cSGeorge Liu 1016fe8751cSGeorge Liu for (const auto& [service, sensorPath] : sensorsServiceAndPath) 1026fe8751cSGeorge Liu { 103deae6a78SEd Tanous dbus::utility::getAllProperties( 1046fe8751cSGeorge Liu *crow::connections::systemBus, service, sensorPath, 1056fe8751cSGeorge Liu "xyz.openbmc_project.Sensor.Value", 1066fe8751cSGeorge Liu [asyncResp, chassisId, 1076fe8751cSGeorge Liu sensorPath](const boost::system::error_code& ec1, 1086fe8751cSGeorge Liu const dbus::utility::DBusPropertiesMap& properties) { 1096fe8751cSGeorge Liu afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1, 1106fe8751cSGeorge Liu properties); 1116fe8751cSGeorge Liu }); 1126fe8751cSGeorge Liu } 1136fe8751cSGeorge Liu } 1146fe8751cSGeorge Liu 1156fe8751cSGeorge Liu inline void getTemperatureReadingsCelsius( 1166fe8751cSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1176fe8751cSGeorge Liu const std::string& validChassisPath, const std::string& chassisId) 1186fe8751cSGeorge Liu { 1196fe8751cSGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1206fe8751cSGeorge Liu "xyz.openbmc_project.Sensor.Value"}; 1216fe8751cSGeorge Liu 1226fe8751cSGeorge Liu sensor_utils::getAllSensorObjects( 1236fe8751cSGeorge Liu validChassisPath, "/xyz/openbmc_project/sensors/temperature", 1246fe8751cSGeorge Liu interfaces, 1, 1256fe8751cSGeorge Liu std::bind_front(handleTemperatureReadingsCelsius, asyncResp, 1266fe8751cSGeorge Liu chassisId)); 1276fe8751cSGeorge Liu } 1286fe8751cSGeorge Liu 129*504af5a0SPatrick Williams inline void doThermalMetrics( 130*504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1315ae1f7f3Szhanghch05 const std::string& chassisId, 1325ae1f7f3Szhanghch05 const std::optional<std::string>& validChassisPath) 1335ae1f7f3Szhanghch05 { 1345ae1f7f3Szhanghch05 if (!validChassisPath) 1355ae1f7f3Szhanghch05 { 1365ae1f7f3Szhanghch05 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 1375ae1f7f3Szhanghch05 return; 1385ae1f7f3Szhanghch05 } 1395ae1f7f3Szhanghch05 1405ae1f7f3Szhanghch05 asyncResp->res.addHeader( 1415ae1f7f3Szhanghch05 boost::beast::http::field::link, 1425ae1f7f3Szhanghch05 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby"); 1435ae1f7f3Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1445ae1f7f3Szhanghch05 "#ThermalMetrics.v1_0_1.ThermalMetrics"; 1455ae1f7f3Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1465ae1f7f3Szhanghch05 "/redfish/v1/Chassis/{}/ThermalSubsystem/ThermalMetrics", chassisId); 1475ae1f7f3Szhanghch05 asyncResp->res.jsonValue["Id"] = "ThermalMetrics"; 1485ae1f7f3Szhanghch05 asyncResp->res.jsonValue["Name"] = "Thermal Metrics"; 1496fe8751cSGeorge Liu 1506fe8751cSGeorge Liu getTemperatureReadingsCelsius(asyncResp, *validChassisPath, chassisId); 1515ae1f7f3Szhanghch05 } 1525ae1f7f3Szhanghch05 1535ae1f7f3Szhanghch05 inline void handleThermalMetricsHead( 1545ae1f7f3Szhanghch05 App& app, const crow::Request& req, 1555ae1f7f3Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1565ae1f7f3Szhanghch05 const std::string& chassisId) 1575ae1f7f3Szhanghch05 { 1585ae1f7f3Szhanghch05 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1595ae1f7f3Szhanghch05 { 1605ae1f7f3Szhanghch05 return; 1615ae1f7f3Szhanghch05 } 1625ae1f7f3Szhanghch05 1635ae1f7f3Szhanghch05 redfish::chassis_utils::getValidChassisPath( 1645ae1f7f3Szhanghch05 asyncResp, chassisId, 1655ae1f7f3Szhanghch05 [asyncResp, 1665ae1f7f3Szhanghch05 chassisId](const std::optional<std::string>& validChassisPath) { 1675ae1f7f3Szhanghch05 if (!validChassisPath) 1685ae1f7f3Szhanghch05 { 169bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 170bd79bce8SPatrick Williams chassisId); 1715ae1f7f3Szhanghch05 return; 1725ae1f7f3Szhanghch05 } 1735ae1f7f3Szhanghch05 asyncResp->res.addHeader( 1745ae1f7f3Szhanghch05 boost::beast::http::field::link, 1755ae1f7f3Szhanghch05 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby"); 1765ae1f7f3Szhanghch05 }); 1775ae1f7f3Szhanghch05 } 1785ae1f7f3Szhanghch05 179*504af5a0SPatrick Williams inline void handleThermalMetricsGet( 180*504af5a0SPatrick Williams App& app, const crow::Request& req, 1815ae1f7f3Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1825ae1f7f3Szhanghch05 const std::string& chassisId) 1835ae1f7f3Szhanghch05 { 1845ae1f7f3Szhanghch05 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1855ae1f7f3Szhanghch05 { 1865ae1f7f3Szhanghch05 return; 1875ae1f7f3Szhanghch05 } 1885ae1f7f3Szhanghch05 1895ae1f7f3Szhanghch05 redfish::chassis_utils::getValidChassisPath( 1905ae1f7f3Szhanghch05 asyncResp, chassisId, 1915ae1f7f3Szhanghch05 std::bind_front(doThermalMetrics, asyncResp, chassisId)); 1925ae1f7f3Szhanghch05 } 1935ae1f7f3Szhanghch05 1945ae1f7f3Szhanghch05 inline void requestRoutesThermalMetrics(App& app) 1955ae1f7f3Szhanghch05 { 1965ae1f7f3Szhanghch05 BMCWEB_ROUTE(app, 1975ae1f7f3Szhanghch05 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/") 1985ae1f7f3Szhanghch05 .privileges(redfish::privileges::headThermalMetrics) 1995ae1f7f3Szhanghch05 .methods(boost::beast::http::verb::head)( 2005ae1f7f3Szhanghch05 std::bind_front(handleThermalMetricsHead, std::ref(app))); 2015ae1f7f3Szhanghch05 2025ae1f7f3Szhanghch05 BMCWEB_ROUTE(app, 2035ae1f7f3Szhanghch05 "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/") 2045ae1f7f3Szhanghch05 .privileges(redfish::privileges::getThermalMetrics) 2055ae1f7f3Szhanghch05 .methods(boost::beast::http::verb::get)( 2065ae1f7f3Szhanghch05 std::bind_front(handleThermalMetricsGet, std::ref(app))); 2075ae1f7f3Szhanghch05 } 2085ae1f7f3Szhanghch05 } // namespace redfish 209