xref: /openbmc/bmcweb/features/redfish/lib/thermal_metrics.hpp (revision 6fe8751c46d7086e49977b68e74262927b4a7d39)
15ae1f7f3Szhanghch05 #pragma once
25ae1f7f3Szhanghch05 
35ae1f7f3Szhanghch05 #include "app.hpp"
4*6fe8751cSGeorge Liu #include "dbus_utility.hpp"
55ae1f7f3Szhanghch05 #include "query.hpp"
65ae1f7f3Szhanghch05 #include "registries/privilege_registry.hpp"
75ae1f7f3Szhanghch05 #include "utils/chassis_utils.hpp"
8*6fe8751cSGeorge Liu #include "utils/json_utils.hpp"
9*6fe8751cSGeorge Liu #include "utils/sensor_utils.hpp"
105ae1f7f3Szhanghch05 
11*6fe8751cSGeorge Liu #include <boost/system/error_code.hpp>
12*6fe8751cSGeorge Liu 
13*6fe8751cSGeorge Liu #include <array>
145ae1f7f3Szhanghch05 #include <functional>
155ae1f7f3Szhanghch05 #include <memory>
165ae1f7f3Szhanghch05 #include <optional>
175ae1f7f3Szhanghch05 #include <string>
18*6fe8751cSGeorge Liu #include <string_view>
195ae1f7f3Szhanghch05 
205ae1f7f3Szhanghch05 namespace redfish
215ae1f7f3Szhanghch05 {
22*6fe8751cSGeorge Liu inline void afterGetTemperatureValue(
23*6fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24*6fe8751cSGeorge Liu     const std::string& chassisId, const std::string& path,
25*6fe8751cSGeorge Liu     const boost::system::error_code& ec,
26*6fe8751cSGeorge Liu     const dbus::utility::DBusPropertiesMap& valuesDict)
27*6fe8751cSGeorge Liu {
28*6fe8751cSGeorge Liu     if (ec)
29*6fe8751cSGeorge Liu     {
30*6fe8751cSGeorge Liu         if (ec.value() != EBADR)
31*6fe8751cSGeorge Liu         {
32*6fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}",
33*6fe8751cSGeorge Liu                              ec.value());
34*6fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
35*6fe8751cSGeorge Liu         }
36*6fe8751cSGeorge Liu         return;
37*6fe8751cSGeorge Liu     }
38*6fe8751cSGeorge Liu 
39*6fe8751cSGeorge Liu     nlohmann::json item = nlohmann::json::object();
40*6fe8751cSGeorge Liu 
41*6fe8751cSGeorge Liu     /* Don't return an error for a failure to fill in properties from any of
42*6fe8751cSGeorge Liu      * the sensors in the list. Just skip it.
43*6fe8751cSGeorge Liu      */
44*6fe8751cSGeorge Liu     if (sensor_utils::objectExcerptToJson(
45*6fe8751cSGeorge Liu             path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode,
46*6fe8751cSGeorge Liu             "temperature", valuesDict, item))
47*6fe8751cSGeorge Liu     {
48*6fe8751cSGeorge Liu         nlohmann::json& temperatureReadings =
49*6fe8751cSGeorge Liu             asyncResp->res.jsonValue["TemperatureReadingsCelsius"];
50*6fe8751cSGeorge Liu         nlohmann::json::array_t* temperatureArray =
51*6fe8751cSGeorge Liu             temperatureReadings.get_ptr<nlohmann::json::array_t*>();
52*6fe8751cSGeorge Liu         if (temperatureArray == nullptr)
53*6fe8751cSGeorge Liu         {
54*6fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array");
55*6fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
56*6fe8751cSGeorge Liu             return;
57*6fe8751cSGeorge Liu         }
58*6fe8751cSGeorge Liu 
59*6fe8751cSGeorge Liu         temperatureArray->emplace_back(std::move(item));
60*6fe8751cSGeorge Liu         asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] =
61*6fe8751cSGeorge Liu             temperatureArray->size();
62*6fe8751cSGeorge Liu 
63*6fe8751cSGeorge Liu         json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri");
64*6fe8751cSGeorge Liu     }
65*6fe8751cSGeorge Liu }
66*6fe8751cSGeorge Liu 
67*6fe8751cSGeorge Liu inline void handleTemperatureReadingsCelsius(
68*6fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
69*6fe8751cSGeorge Liu     const std::string& chassisId, const boost::system::error_code& ec,
70*6fe8751cSGeorge Liu     const sensor_utils::SensorServicePathList& sensorsServiceAndPath)
71*6fe8751cSGeorge Liu {
72*6fe8751cSGeorge Liu     if (ec)
73*6fe8751cSGeorge Liu     {
74*6fe8751cSGeorge Liu         if (ec.value() != EBADR)
75*6fe8751cSGeorge Liu         {
76*6fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}",
77*6fe8751cSGeorge Liu                              ec.value());
78*6fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
79*6fe8751cSGeorge Liu         }
80*6fe8751cSGeorge Liu         return;
81*6fe8751cSGeorge Liu     }
82*6fe8751cSGeorge Liu 
83*6fe8751cSGeorge Liu     asyncResp->res.jsonValue["TemperatureReadingsCelsius"] =
84*6fe8751cSGeorge Liu         nlohmann::json::array_t();
85*6fe8751cSGeorge Liu     asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0;
86*6fe8751cSGeorge Liu 
87*6fe8751cSGeorge Liu     for (const auto& [service, sensorPath] : sensorsServiceAndPath)
88*6fe8751cSGeorge Liu     {
89*6fe8751cSGeorge Liu         sdbusplus::asio::getAllProperties(
90*6fe8751cSGeorge Liu             *crow::connections::systemBus, service, sensorPath,
91*6fe8751cSGeorge Liu             "xyz.openbmc_project.Sensor.Value",
92*6fe8751cSGeorge Liu             [asyncResp, chassisId,
93*6fe8751cSGeorge Liu              sensorPath](const boost::system::error_code& ec1,
94*6fe8751cSGeorge Liu                          const dbus::utility::DBusPropertiesMap& properties) {
95*6fe8751cSGeorge Liu                 afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1,
96*6fe8751cSGeorge Liu                                          properties);
97*6fe8751cSGeorge Liu             });
98*6fe8751cSGeorge Liu     }
99*6fe8751cSGeorge Liu }
100*6fe8751cSGeorge Liu 
101*6fe8751cSGeorge Liu inline void getTemperatureReadingsCelsius(
102*6fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103*6fe8751cSGeorge Liu     const std::string& validChassisPath, const std::string& chassisId)
104*6fe8751cSGeorge Liu {
105*6fe8751cSGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
106*6fe8751cSGeorge Liu         "xyz.openbmc_project.Sensor.Value"};
107*6fe8751cSGeorge Liu 
108*6fe8751cSGeorge Liu     sensor_utils::getAllSensorObjects(
109*6fe8751cSGeorge Liu         validChassisPath, "/xyz/openbmc_project/sensors/temperature",
110*6fe8751cSGeorge Liu         interfaces, 1,
111*6fe8751cSGeorge Liu         std::bind_front(handleTemperatureReadingsCelsius, asyncResp,
112*6fe8751cSGeorge Liu                         chassisId));
113*6fe8751cSGeorge Liu }
114*6fe8751cSGeorge Liu 
1155ae1f7f3Szhanghch05 inline void
1165ae1f7f3Szhanghch05     doThermalMetrics(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1175ae1f7f3Szhanghch05                      const std::string& chassisId,
1185ae1f7f3Szhanghch05                      const std::optional<std::string>& validChassisPath)
1195ae1f7f3Szhanghch05 {
1205ae1f7f3Szhanghch05     if (!validChassisPath)
1215ae1f7f3Szhanghch05     {
1225ae1f7f3Szhanghch05         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
1235ae1f7f3Szhanghch05         return;
1245ae1f7f3Szhanghch05     }
1255ae1f7f3Szhanghch05 
1265ae1f7f3Szhanghch05     asyncResp->res.addHeader(
1275ae1f7f3Szhanghch05         boost::beast::http::field::link,
1285ae1f7f3Szhanghch05         "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
1295ae1f7f3Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
1305ae1f7f3Szhanghch05         "#ThermalMetrics.v1_0_1.ThermalMetrics";
1315ae1f7f3Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1325ae1f7f3Szhanghch05         "/redfish/v1/Chassis/{}/ThermalSubsystem/ThermalMetrics", chassisId);
1335ae1f7f3Szhanghch05     asyncResp->res.jsonValue["Id"] = "ThermalMetrics";
1345ae1f7f3Szhanghch05     asyncResp->res.jsonValue["Name"] = "Thermal Metrics";
135*6fe8751cSGeorge Liu 
136*6fe8751cSGeorge Liu     getTemperatureReadingsCelsius(asyncResp, *validChassisPath, chassisId);
1375ae1f7f3Szhanghch05 }
1385ae1f7f3Szhanghch05 
1395ae1f7f3Szhanghch05 inline void handleThermalMetricsHead(
1405ae1f7f3Szhanghch05     App& app, const crow::Request& req,
1415ae1f7f3Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1425ae1f7f3Szhanghch05     const std::string& chassisId)
1435ae1f7f3Szhanghch05 {
1445ae1f7f3Szhanghch05     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1455ae1f7f3Szhanghch05     {
1465ae1f7f3Szhanghch05         return;
1475ae1f7f3Szhanghch05     }
1485ae1f7f3Szhanghch05 
1495ae1f7f3Szhanghch05     redfish::chassis_utils::getValidChassisPath(
1505ae1f7f3Szhanghch05         asyncResp, chassisId,
1515ae1f7f3Szhanghch05         [asyncResp,
1525ae1f7f3Szhanghch05          chassisId](const std::optional<std::string>& validChassisPath) {
1535ae1f7f3Szhanghch05             if (!validChassisPath)
1545ae1f7f3Szhanghch05             {
155bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Chassis",
156bd79bce8SPatrick Williams                                            chassisId);
1575ae1f7f3Szhanghch05                 return;
1585ae1f7f3Szhanghch05             }
1595ae1f7f3Szhanghch05             asyncResp->res.addHeader(
1605ae1f7f3Szhanghch05                 boost::beast::http::field::link,
1615ae1f7f3Szhanghch05                 "</redfish/v1/JsonSchemas/ThermalMetrics/ThermalMetrics.json>; rel=describedby");
1625ae1f7f3Szhanghch05         });
1635ae1f7f3Szhanghch05 }
1645ae1f7f3Szhanghch05 
1655ae1f7f3Szhanghch05 inline void
1665ae1f7f3Szhanghch05     handleThermalMetricsGet(App& app, const crow::Request& req,
1675ae1f7f3Szhanghch05                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1685ae1f7f3Szhanghch05                             const std::string& chassisId)
1695ae1f7f3Szhanghch05 {
1705ae1f7f3Szhanghch05     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1715ae1f7f3Szhanghch05     {
1725ae1f7f3Szhanghch05         return;
1735ae1f7f3Szhanghch05     }
1745ae1f7f3Szhanghch05 
1755ae1f7f3Szhanghch05     redfish::chassis_utils::getValidChassisPath(
1765ae1f7f3Szhanghch05         asyncResp, chassisId,
1775ae1f7f3Szhanghch05         std::bind_front(doThermalMetrics, asyncResp, chassisId));
1785ae1f7f3Szhanghch05 }
1795ae1f7f3Szhanghch05 
1805ae1f7f3Szhanghch05 inline void requestRoutesThermalMetrics(App& app)
1815ae1f7f3Szhanghch05 {
1825ae1f7f3Szhanghch05     BMCWEB_ROUTE(app,
1835ae1f7f3Szhanghch05                  "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
1845ae1f7f3Szhanghch05         .privileges(redfish::privileges::headThermalMetrics)
1855ae1f7f3Szhanghch05         .methods(boost::beast::http::verb::head)(
1865ae1f7f3Szhanghch05             std::bind_front(handleThermalMetricsHead, std::ref(app)));
1875ae1f7f3Szhanghch05 
1885ae1f7f3Szhanghch05     BMCWEB_ROUTE(app,
1895ae1f7f3Szhanghch05                  "/redfish/v1/Chassis/<str>/ThermalSubsystem/ThermalMetrics/")
1905ae1f7f3Szhanghch05         .privileges(redfish::privileges::getThermalMetrics)
1915ae1f7f3Szhanghch05         .methods(boost::beast::http::verb::get)(
1925ae1f7f3Szhanghch05             std::bind_front(handleThermalMetricsGet, std::ref(app)));
1935ae1f7f3Szhanghch05 }
1945ae1f7f3Szhanghch05 } // namespace redfish
195