xref: /openbmc/bmcweb/features/redfish/lib/thermal_metrics.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
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