xref: /openbmc/bmcweb/features/redfish/lib/thermal_metrics.hpp (revision deae6a789444debc4724fb6902fc5def299afbee)
15ae1f7f3Szhanghch05 #pragma once
25ae1f7f3Szhanghch05 
35ae1f7f3Szhanghch05 #include "app.hpp"
46fe8751cSGeorge Liu #include "dbus_utility.hpp"
55ae1f7f3Szhanghch05 #include "query.hpp"
65ae1f7f3Szhanghch05 #include "registries/privilege_registry.hpp"
75ae1f7f3Szhanghch05 #include "utils/chassis_utils.hpp"
86fe8751cSGeorge Liu #include "utils/json_utils.hpp"
96fe8751cSGeorge Liu #include "utils/sensor_utils.hpp"
105ae1f7f3Szhanghch05 
116fe8751cSGeorge Liu #include <boost/system/error_code.hpp>
126fe8751cSGeorge Liu 
136fe8751cSGeorge Liu #include <array>
145ae1f7f3Szhanghch05 #include <functional>
155ae1f7f3Szhanghch05 #include <memory>
165ae1f7f3Szhanghch05 #include <optional>
175ae1f7f3Szhanghch05 #include <string>
186fe8751cSGeorge Liu #include <string_view>
195ae1f7f3Szhanghch05 
205ae1f7f3Szhanghch05 namespace redfish
215ae1f7f3Szhanghch05 {
226fe8751cSGeorge Liu inline void afterGetTemperatureValue(
236fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
246fe8751cSGeorge Liu     const std::string& chassisId, const std::string& path,
256fe8751cSGeorge Liu     const boost::system::error_code& ec,
266fe8751cSGeorge Liu     const dbus::utility::DBusPropertiesMap& valuesDict)
276fe8751cSGeorge Liu {
286fe8751cSGeorge Liu     if (ec)
296fe8751cSGeorge Liu     {
306fe8751cSGeorge Liu         if (ec.value() != EBADR)
316fe8751cSGeorge Liu         {
326fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error for getAllProperties {}",
336fe8751cSGeorge Liu                              ec.value());
346fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
356fe8751cSGeorge Liu         }
366fe8751cSGeorge Liu         return;
376fe8751cSGeorge Liu     }
386fe8751cSGeorge Liu 
396fe8751cSGeorge Liu     nlohmann::json item = nlohmann::json::object();
406fe8751cSGeorge Liu 
416fe8751cSGeorge Liu     /* Don't return an error for a failure to fill in properties from any of
426fe8751cSGeorge Liu      * the sensors in the list. Just skip it.
436fe8751cSGeorge Liu      */
446fe8751cSGeorge Liu     if (sensor_utils::objectExcerptToJson(
456fe8751cSGeorge Liu             path, chassisId, sensor_utils::ChassisSubNode::thermalMetricsNode,
466fe8751cSGeorge Liu             "temperature", valuesDict, item))
476fe8751cSGeorge Liu     {
486fe8751cSGeorge Liu         nlohmann::json& temperatureReadings =
496fe8751cSGeorge Liu             asyncResp->res.jsonValue["TemperatureReadingsCelsius"];
506fe8751cSGeorge Liu         nlohmann::json::array_t* temperatureArray =
516fe8751cSGeorge Liu             temperatureReadings.get_ptr<nlohmann::json::array_t*>();
526fe8751cSGeorge Liu         if (temperatureArray == nullptr)
536fe8751cSGeorge Liu         {
546fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("Missing TemperatureReadingsCelsius Json array");
556fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
566fe8751cSGeorge Liu             return;
576fe8751cSGeorge Liu         }
586fe8751cSGeorge Liu 
596fe8751cSGeorge Liu         temperatureArray->emplace_back(std::move(item));
606fe8751cSGeorge Liu         asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] =
616fe8751cSGeorge Liu             temperatureArray->size();
626fe8751cSGeorge Liu 
636fe8751cSGeorge Liu         json_util::sortJsonArrayByKey(*temperatureArray, "DataSourceUri");
646fe8751cSGeorge Liu     }
656fe8751cSGeorge Liu }
666fe8751cSGeorge Liu 
676fe8751cSGeorge Liu inline void handleTemperatureReadingsCelsius(
686fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
696fe8751cSGeorge Liu     const std::string& chassisId, const boost::system::error_code& ec,
706fe8751cSGeorge Liu     const sensor_utils::SensorServicePathList& sensorsServiceAndPath)
716fe8751cSGeorge Liu {
726fe8751cSGeorge Liu     if (ec)
736fe8751cSGeorge Liu     {
746fe8751cSGeorge Liu         if (ec.value() != EBADR)
756fe8751cSGeorge Liu         {
766fe8751cSGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error for getAssociatedSubTree {}",
776fe8751cSGeorge Liu                              ec.value());
786fe8751cSGeorge Liu             messages::internalError(asyncResp->res);
796fe8751cSGeorge Liu         }
806fe8751cSGeorge Liu         return;
816fe8751cSGeorge Liu     }
826fe8751cSGeorge Liu 
836fe8751cSGeorge Liu     asyncResp->res.jsonValue["TemperatureReadingsCelsius"] =
846fe8751cSGeorge Liu         nlohmann::json::array_t();
856fe8751cSGeorge Liu     asyncResp->res.jsonValue["TemperatureReadingsCelsius@odata.count"] = 0;
866fe8751cSGeorge Liu 
876fe8751cSGeorge Liu     for (const auto& [service, sensorPath] : sensorsServiceAndPath)
886fe8751cSGeorge Liu     {
89*deae6a78SEd Tanous         dbus::utility::getAllProperties(
906fe8751cSGeorge Liu             *crow::connections::systemBus, service, sensorPath,
916fe8751cSGeorge Liu             "xyz.openbmc_project.Sensor.Value",
926fe8751cSGeorge Liu             [asyncResp, chassisId,
936fe8751cSGeorge Liu              sensorPath](const boost::system::error_code& ec1,
946fe8751cSGeorge Liu                          const dbus::utility::DBusPropertiesMap& properties) {
956fe8751cSGeorge Liu                 afterGetTemperatureValue(asyncResp, chassisId, sensorPath, ec1,
966fe8751cSGeorge Liu                                          properties);
976fe8751cSGeorge Liu             });
986fe8751cSGeorge Liu     }
996fe8751cSGeorge Liu }
1006fe8751cSGeorge Liu 
1016fe8751cSGeorge Liu inline void getTemperatureReadingsCelsius(
1026fe8751cSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1036fe8751cSGeorge Liu     const std::string& validChassisPath, const std::string& chassisId)
1046fe8751cSGeorge Liu {
1056fe8751cSGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1066fe8751cSGeorge Liu         "xyz.openbmc_project.Sensor.Value"};
1076fe8751cSGeorge Liu 
1086fe8751cSGeorge Liu     sensor_utils::getAllSensorObjects(
1096fe8751cSGeorge Liu         validChassisPath, "/xyz/openbmc_project/sensors/temperature",
1106fe8751cSGeorge Liu         interfaces, 1,
1116fe8751cSGeorge Liu         std::bind_front(handleTemperatureReadingsCelsius, asyncResp,
1126fe8751cSGeorge Liu                         chassisId));
1136fe8751cSGeorge Liu }
1146fe8751cSGeorge 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";
1356fe8751cSGeorge Liu 
1366fe8751cSGeorge 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