140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
39516f41fSGeorge Liu #pragma once
49516f41fSGeorge Liu
59516f41fSGeorge Liu #include "app.hpp"
6d7857201SEd Tanous #include "async_resp.hpp"
79516f41fSGeorge Liu #include "dbus_utility.hpp"
89516f41fSGeorge Liu #include "error_messages.hpp"
9539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
10d7857201SEd Tanous #include "http_request.hpp"
11d7857201SEd Tanous #include "logging.hpp"
129516f41fSGeorge Liu #include "query.hpp"
139516f41fSGeorge Liu #include "registries/privilege_registry.hpp"
149516f41fSGeorge Liu #include "utils/chassis_utils.hpp"
159516f41fSGeorge Liu
16d7857201SEd Tanous #include <asm-generic/errno.h>
17d7857201SEd Tanous
18d7857201SEd Tanous #include <boost/beast/http/field.hpp>
19d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
209f1ae5aeSAlbert Zhang #include <boost/system/error_code.hpp>
219516f41fSGeorge Liu #include <boost/url/format.hpp>
22d7857201SEd Tanous #include <nlohmann/json.hpp>
23d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp>
249516f41fSGeorge Liu
25d7857201SEd Tanous #include <array>
269516f41fSGeorge Liu #include <functional>
279516f41fSGeorge Liu #include <memory>
289516f41fSGeorge Liu #include <optional>
299516f41fSGeorge Liu #include <string>
309516f41fSGeorge Liu #include <string_view>
31d7857201SEd Tanous #include <utility>
329516f41fSGeorge Liu
339516f41fSGeorge Liu namespace redfish
349516f41fSGeorge Liu {
359516f41fSGeorge Liu constexpr std::array<std::string_view, 1> fanInterface = {
369516f41fSGeorge Liu "xyz.openbmc_project.Inventory.Item.Fan"};
379516f41fSGeorge Liu
updateFanList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const dbus::utility::MapperGetSubTreePathsResponse & fanPaths)38*504af5a0SPatrick Williams inline void updateFanList(
39*504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
409516f41fSGeorge Liu const std::string& chassisId,
419516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths)
429516f41fSGeorge Liu {
439516f41fSGeorge Liu nlohmann::json& fanList = asyncResp->res.jsonValue["Members"];
449516f41fSGeorge Liu for (const std::string& fanPath : fanPaths)
459516f41fSGeorge Liu {
469516f41fSGeorge Liu std::string fanName =
479516f41fSGeorge Liu sdbusplus::message::object_path(fanPath).filename();
489516f41fSGeorge Liu if (fanName.empty())
499516f41fSGeorge Liu {
509516f41fSGeorge Liu continue;
519516f41fSGeorge Liu }
529516f41fSGeorge Liu
539516f41fSGeorge Liu nlohmann::json item = nlohmann::json::object();
549516f41fSGeorge Liu item["@odata.id"] = boost::urls::format(
559516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId,
569516f41fSGeorge Liu fanName);
579516f41fSGeorge Liu
589516f41fSGeorge Liu fanList.emplace_back(std::move(item));
599516f41fSGeorge Liu }
609516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = fanList.size();
619516f41fSGeorge Liu }
629516f41fSGeorge Liu
getFanPaths(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & validChassisPath,const std::function<void (const dbus::utility::MapperGetSubTreePathsResponse & fanPaths)> & callback)639516f41fSGeorge Liu inline void getFanPaths(
649516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
65d547d8d2SEd Tanous const std::string& validChassisPath,
669516f41fSGeorge Liu const std::function<void(const dbus::utility::MapperGetSubTreePathsResponse&
679516f41fSGeorge Liu fanPaths)>& callback)
689516f41fSGeorge Liu {
69d547d8d2SEd Tanous sdbusplus::message::object_path endpointPath{validChassisPath};
709516f41fSGeorge Liu endpointPath /= "cooled_by";
719516f41fSGeorge Liu
729516f41fSGeorge Liu dbus::utility::getAssociatedSubTreePaths(
739516f41fSGeorge Liu endpointPath,
749516f41fSGeorge Liu sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
759516f41fSGeorge Liu fanInterface,
769516f41fSGeorge Liu [asyncResp, callback](
779516f41fSGeorge Liu const boost::system::error_code& ec,
789516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
799516f41fSGeorge Liu if (ec)
809516f41fSGeorge Liu {
819516f41fSGeorge Liu if (ec.value() != EBADR)
829516f41fSGeorge Liu {
8362598e31SEd Tanous BMCWEB_LOG_ERROR(
8462598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}",
8562598e31SEd Tanous ec.value());
869516f41fSGeorge Liu messages::internalError(asyncResp->res);
879516f41fSGeorge Liu }
889516f41fSGeorge Liu return;
899516f41fSGeorge Liu }
909516f41fSGeorge Liu callback(subtreePaths);
919516f41fSGeorge Liu });
929516f41fSGeorge Liu }
939516f41fSGeorge Liu
doFanCollection(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::optional<std::string> & validChassisPath)949516f41fSGeorge Liu inline void doFanCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
959516f41fSGeorge Liu const std::string& chassisId,
969516f41fSGeorge Liu const std::optional<std::string>& validChassisPath)
979516f41fSGeorge Liu {
989516f41fSGeorge Liu if (!validChassisPath)
999516f41fSGeorge Liu {
1009516f41fSGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
1019516f41fSGeorge Liu return;
1029516f41fSGeorge Liu }
1039516f41fSGeorge Liu
1049516f41fSGeorge Liu asyncResp->res.addHeader(
1059516f41fSGeorge Liu boost::beast::http::field::link,
1069516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby");
1079516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.type"] = "#FanCollection.FanCollection";
1089516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1099516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans", chassisId);
1109516f41fSGeorge Liu asyncResp->res.jsonValue["Name"] = "Fan Collection";
1119516f41fSGeorge Liu asyncResp->res.jsonValue["Description"] =
1129516f41fSGeorge Liu "The collection of Fan resource instances " + chassisId;
1139516f41fSGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1149516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0;
1159516f41fSGeorge Liu
116d547d8d2SEd Tanous getFanPaths(asyncResp, *validChassisPath,
1179516f41fSGeorge Liu std::bind_front(updateFanList, asyncResp, chassisId));
1189516f41fSGeorge Liu }
1199516f41fSGeorge Liu
handleFanCollectionHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)120*504af5a0SPatrick Williams inline void handleFanCollectionHead(
121*504af5a0SPatrick Williams App& app, const crow::Request& req,
1229516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1239516f41fSGeorge Liu const std::string& chassisId)
1249516f41fSGeorge Liu {
1259516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1269516f41fSGeorge Liu {
1279516f41fSGeorge Liu return;
1289516f41fSGeorge Liu }
1299516f41fSGeorge Liu
1309516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath(
1319516f41fSGeorge Liu asyncResp, chassisId,
1329516f41fSGeorge Liu [asyncResp,
1339516f41fSGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) {
1349516f41fSGeorge Liu if (!validChassisPath)
1359516f41fSGeorge Liu {
136bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis",
137bd79bce8SPatrick Williams chassisId);
1389516f41fSGeorge Liu return;
1399516f41fSGeorge Liu }
1409516f41fSGeorge Liu asyncResp->res.addHeader(
1419516f41fSGeorge Liu boost::beast::http::field::link,
1429516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby");
1439516f41fSGeorge Liu });
1449516f41fSGeorge Liu }
1459516f41fSGeorge Liu
handleFanCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)146*504af5a0SPatrick Williams inline void handleFanCollectionGet(
147*504af5a0SPatrick Williams App& app, const crow::Request& req,
1489516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1499516f41fSGeorge Liu const std::string& chassisId)
1509516f41fSGeorge Liu {
1519516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1529516f41fSGeorge Liu {
1539516f41fSGeorge Liu return;
1549516f41fSGeorge Liu }
1559516f41fSGeorge Liu
1569516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath(
1579516f41fSGeorge Liu asyncResp, chassisId,
1589516f41fSGeorge Liu std::bind_front(doFanCollection, asyncResp, chassisId));
1599516f41fSGeorge Liu }
1609516f41fSGeorge Liu
requestRoutesFanCollection(App & app)1619516f41fSGeorge Liu inline void requestRoutesFanCollection(App& app)
1629516f41fSGeorge Liu {
1639516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/")
1649516f41fSGeorge Liu .privileges(redfish::privileges::headFanCollection)
1659516f41fSGeorge Liu .methods(boost::beast::http::verb::head)(
1669516f41fSGeorge Liu std::bind_front(handleFanCollectionHead, std::ref(app)));
1679516f41fSGeorge Liu
1689516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/")
1699516f41fSGeorge Liu .privileges(redfish::privileges::getFanCollection)
1709516f41fSGeorge Liu .methods(boost::beast::http::verb::get)(
1719516f41fSGeorge Liu std::bind_front(handleFanCollectionGet, std::ref(app)));
1729516f41fSGeorge Liu }
1739516f41fSGeorge Liu
checkFanId(const std::string & fanPath,const std::string & fanId)174e4e54232SGeorge Liu inline bool checkFanId(const std::string& fanPath, const std::string& fanId)
175e4e54232SGeorge Liu {
176e4e54232SGeorge Liu std::string fanName = sdbusplus::message::object_path(fanPath).filename();
177e4e54232SGeorge Liu
178e4e54232SGeorge Liu return !(fanName.empty() || fanName != fanId);
179e4e54232SGeorge Liu }
180e4e54232SGeorge Liu
handleFanPath(const std::string & fanId,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::MapperGetSubTreePathsResponse & fanPaths,const std::function<void (const std::string & fanPath,const std::string & service)> & callback)1814ff0f1f4SEd Tanous inline void handleFanPath(
182e4e54232SGeorge Liu const std::string& fanId,
183e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
184e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths,
185e4e54232SGeorge Liu const std::function<void(const std::string& fanPath,
186e4e54232SGeorge Liu const std::string& service)>& callback)
187e4e54232SGeorge Liu {
188e4e54232SGeorge Liu for (const auto& fanPath : fanPaths)
189e4e54232SGeorge Liu {
190e4e54232SGeorge Liu if (!checkFanId(fanPath, fanId))
191e4e54232SGeorge Liu {
192e4e54232SGeorge Liu continue;
193e4e54232SGeorge Liu }
194e4e54232SGeorge Liu dbus::utility::getDbusObject(
195e4e54232SGeorge Liu fanPath, fanInterface,
196e4e54232SGeorge Liu [fanPath, asyncResp,
197e4e54232SGeorge Liu callback](const boost::system::error_code& ec,
198e4e54232SGeorge Liu const dbus::utility::MapperGetObject& object) {
199e4e54232SGeorge Liu if (ec || object.empty())
200e4e54232SGeorge Liu {
20162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}",
20262598e31SEd Tanous ec.value());
203e4e54232SGeorge Liu messages::internalError(asyncResp->res);
204e4e54232SGeorge Liu return;
205e4e54232SGeorge Liu }
206e4e54232SGeorge Liu callback(fanPath, object.begin()->first);
207e4e54232SGeorge Liu });
208e4e54232SGeorge Liu
209e4e54232SGeorge Liu return;
210e4e54232SGeorge Liu }
21162598e31SEd Tanous BMCWEB_LOG_WARNING("Fan not found {}", fanId);
212e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Fan", fanId);
213e4e54232SGeorge Liu }
214e4e54232SGeorge Liu
getValidFanPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & validChassisPath,const std::string & fanId,const std::function<void (const std::string & fanPath,const std::string & service)> & callback)215e4e54232SGeorge Liu inline void getValidFanPath(
216e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
217e4e54232SGeorge Liu const std::string& validChassisPath, const std::string& fanId,
218e4e54232SGeorge Liu const std::function<void(const std::string& fanPath,
219e4e54232SGeorge Liu const std::string& service)>& callback)
220e4e54232SGeorge Liu {
221e4e54232SGeorge Liu getFanPaths(
222e4e54232SGeorge Liu asyncResp, validChassisPath,
223e4e54232SGeorge Liu [fanId, asyncResp, callback](
224e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) {
225e4e54232SGeorge Liu handleFanPath(fanId, asyncResp, fanPaths, callback);
226e4e54232SGeorge Liu });
227e4e54232SGeorge Liu }
228e4e54232SGeorge Liu
addFanCommonProperties(crow::Response & resp,const std::string & chassisId,const std::string & fanId)229e4e54232SGeorge Liu inline void addFanCommonProperties(crow::Response& resp,
230e4e54232SGeorge Liu const std::string& chassisId,
231e4e54232SGeorge Liu const std::string& fanId)
232e4e54232SGeorge Liu {
233e4e54232SGeorge Liu resp.addHeader(boost::beast::http::field::link,
234e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby");
235e4e54232SGeorge Liu resp.jsonValue["@odata.type"] = "#Fan.v1_3_0.Fan";
236e4e54232SGeorge Liu resp.jsonValue["Name"] = "Fan";
237e4e54232SGeorge Liu resp.jsonValue["Id"] = fanId;
238e4e54232SGeorge Liu resp.jsonValue["@odata.id"] = boost::urls::format(
239e4e54232SGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, fanId);
240539d8c6bSEd Tanous resp.jsonValue["Status"]["State"] = resource::State::Enabled;
241539d8c6bSEd Tanous resp.jsonValue["Status"]["Health"] = resource::Health::OK;
2429f1ae5aeSAlbert Zhang }
2439f1ae5aeSAlbert Zhang
getFanHealth(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & fanPath,const std::string & service)2449f1ae5aeSAlbert Zhang inline void getFanHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2459f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service)
2469f1ae5aeSAlbert Zhang {
247deae6a78SEd Tanous dbus::utility::getProperty<bool>(
248deae6a78SEd Tanous service, fanPath,
2499f1ae5aeSAlbert Zhang "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
2509f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) {
2519f1ae5aeSAlbert Zhang if (ec)
2529f1ae5aeSAlbert Zhang {
2539f1ae5aeSAlbert Zhang if (ec.value() != EBADR)
2549f1ae5aeSAlbert Zhang {
25562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}",
25662598e31SEd Tanous ec.value());
2579f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res);
2589f1ae5aeSAlbert Zhang }
2599f1ae5aeSAlbert Zhang return;
2609f1ae5aeSAlbert Zhang }
2619f1ae5aeSAlbert Zhang
2629f1ae5aeSAlbert Zhang if (!value)
2639f1ae5aeSAlbert Zhang {
264539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] =
265539d8c6bSEd Tanous resource::Health::Critical;
2669f1ae5aeSAlbert Zhang }
2679f1ae5aeSAlbert Zhang });
2689f1ae5aeSAlbert Zhang }
2699f1ae5aeSAlbert Zhang
getFanState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & fanPath,const std::string & service)2709f1ae5aeSAlbert Zhang inline void getFanState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2719f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service)
2729f1ae5aeSAlbert Zhang {
273deae6a78SEd Tanous dbus::utility::getProperty<bool>(
274deae6a78SEd Tanous service, fanPath, "xyz.openbmc_project.Inventory.Item", "Present",
2759f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) {
2769f1ae5aeSAlbert Zhang if (ec)
2779f1ae5aeSAlbert Zhang {
2789f1ae5aeSAlbert Zhang if (ec.value() != EBADR)
2799f1ae5aeSAlbert Zhang {
28062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}",
28162598e31SEd Tanous ec.value());
2829f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res);
2839f1ae5aeSAlbert Zhang }
2849f1ae5aeSAlbert Zhang return;
2859f1ae5aeSAlbert Zhang }
2869f1ae5aeSAlbert Zhang
2879f1ae5aeSAlbert Zhang if (!value)
2889f1ae5aeSAlbert Zhang {
289539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] =
290539d8c6bSEd Tanous resource::State::Absent;
2919f1ae5aeSAlbert Zhang }
2929f1ae5aeSAlbert Zhang });
293e4e54232SGeorge Liu }
294e4e54232SGeorge Liu
getFanAsset(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & fanPath,const std::string & service)295090ae7baSGeorge Liu inline void getFanAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296090ae7baSGeorge Liu const std::string& fanPath, const std::string& service)
297090ae7baSGeorge Liu {
298deae6a78SEd Tanous dbus::utility::getAllProperties(
299deae6a78SEd Tanous service, fanPath, "xyz.openbmc_project.Inventory.Decorator.Asset",
300090ae7baSGeorge Liu [fanPath, asyncResp{asyncResp}](
301090ae7baSGeorge Liu const boost::system::error_code& ec,
302090ae7baSGeorge Liu const dbus::utility::DBusPropertiesMap& assetList) {
303090ae7baSGeorge Liu if (ec)
304090ae7baSGeorge Liu {
305090ae7baSGeorge Liu if (ec.value() != EBADR)
306090ae7baSGeorge Liu {
30762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
30862598e31SEd Tanous ec.value());
309090ae7baSGeorge Liu messages::internalError(asyncResp->res);
310090ae7baSGeorge Liu }
311090ae7baSGeorge Liu return;
312090ae7baSGeorge Liu }
313090ae7baSGeorge Liu const std::string* manufacturer = nullptr;
314090ae7baSGeorge Liu const std::string* model = nullptr;
315090ae7baSGeorge Liu const std::string* partNumber = nullptr;
316090ae7baSGeorge Liu const std::string* serialNumber = nullptr;
317090ae7baSGeorge Liu const std::string* sparePartNumber = nullptr;
318090ae7baSGeorge Liu
319090ae7baSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow(
320090ae7baSGeorge Liu dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
321090ae7baSGeorge Liu manufacturer, "Model", model, "PartNumber", partNumber,
322bd79bce8SPatrick Williams "SerialNumber", serialNumber, "SparePartNumber",
323bd79bce8SPatrick Williams sparePartNumber);
324090ae7baSGeorge Liu if (!success)
325090ae7baSGeorge Liu {
326090ae7baSGeorge Liu messages::internalError(asyncResp->res);
327090ae7baSGeorge Liu return;
328090ae7baSGeorge Liu }
329090ae7baSGeorge Liu if (manufacturer != nullptr)
330090ae7baSGeorge Liu {
331090ae7baSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
332090ae7baSGeorge Liu }
333090ae7baSGeorge Liu if (model != nullptr)
334090ae7baSGeorge Liu {
335090ae7baSGeorge Liu asyncResp->res.jsonValue["Model"] = *model;
336090ae7baSGeorge Liu }
337090ae7baSGeorge Liu if (partNumber != nullptr)
338090ae7baSGeorge Liu {
339090ae7baSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber;
340090ae7baSGeorge Liu }
341090ae7baSGeorge Liu if (serialNumber != nullptr)
342090ae7baSGeorge Liu {
343090ae7baSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
344090ae7baSGeorge Liu }
345090ae7baSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty())
346090ae7baSGeorge Liu {
347090ae7baSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
348090ae7baSGeorge Liu }
349090ae7baSGeorge Liu });
350090ae7baSGeorge Liu }
351090ae7baSGeorge Liu
getFanLocation(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & fanPath,const std::string & service)352fc3edfddSEd Tanous inline void getFanLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3534a2e485dSGeorge Liu const std::string& fanPath,
3544a2e485dSGeorge Liu const std::string& service)
3554a2e485dSGeorge Liu {
356deae6a78SEd Tanous dbus::utility::getProperty<std::string>(
357deae6a78SEd Tanous service, fanPath,
3584a2e485dSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
359fc3edfddSEd Tanous [asyncResp](const boost::system::error_code& ec,
3604a2e485dSGeorge Liu const std::string& property) {
3614a2e485dSGeorge Liu if (ec)
3624a2e485dSGeorge Liu {
3634a2e485dSGeorge Liu if (ec.value() != EBADR)
3644a2e485dSGeorge Liu {
36562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location{}",
36662598e31SEd Tanous ec.value());
367fc3edfddSEd Tanous messages::internalError(asyncResp->res);
3684a2e485dSGeorge Liu }
3694a2e485dSGeorge Liu return;
3704a2e485dSGeorge Liu }
371bd79bce8SPatrick Williams asyncResp->res
372bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3734a2e485dSGeorge Liu property;
3744a2e485dSGeorge Liu });
3754a2e485dSGeorge Liu }
3764a2e485dSGeorge Liu
afterGetValidFanPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & fanId,const std::string & fanPath,const std::string & service)377*504af5a0SPatrick Williams inline void afterGetValidFanPath(
378*504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
379e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId,
380e4e54232SGeorge Liu const std::string& fanPath, const std::string& service)
381e4e54232SGeorge Liu {
382e4e54232SGeorge Liu addFanCommonProperties(asyncResp->res, chassisId, fanId);
3839f1ae5aeSAlbert Zhang getFanState(asyncResp, fanPath, service);
3849f1ae5aeSAlbert Zhang getFanHealth(asyncResp, fanPath, service);
385090ae7baSGeorge Liu getFanAsset(asyncResp, fanPath, service);
3864a2e485dSGeorge Liu getFanLocation(asyncResp, fanPath, service);
387e4e54232SGeorge Liu }
388e4e54232SGeorge Liu
doFanGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & fanId,const std::optional<std::string> & validChassisPath)389e4e54232SGeorge Liu inline void doFanGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
390e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId,
391e4e54232SGeorge Liu const std::optional<std::string>& validChassisPath)
392e4e54232SGeorge Liu {
393e4e54232SGeorge Liu if (!validChassisPath)
394e4e54232SGeorge Liu {
395e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
396e4e54232SGeorge Liu return;
397e4e54232SGeorge Liu }
398e4e54232SGeorge Liu
399e4e54232SGeorge Liu getValidFanPath(
400e4e54232SGeorge Liu asyncResp, *validChassisPath, fanId,
401e4e54232SGeorge Liu std::bind_front(afterGetValidFanPath, asyncResp, chassisId, fanId));
402e4e54232SGeorge Liu }
403e4e54232SGeorge Liu
handleFanHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & fanId)404e4e54232SGeorge Liu inline void handleFanHead(App& app, const crow::Request& req,
405e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
406e4e54232SGeorge Liu const std::string& chassisId,
407e4e54232SGeorge Liu const std::string& fanId)
408e4e54232SGeorge Liu {
409e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp))
410e4e54232SGeorge Liu {
411e4e54232SGeorge Liu return;
412e4e54232SGeorge Liu }
413e4e54232SGeorge Liu
414e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath(
415e4e54232SGeorge Liu asyncResp, chassisId,
416e4e54232SGeorge Liu [asyncResp, chassisId,
417e4e54232SGeorge Liu fanId](const std::optional<std::string>& validChassisPath) {
418e4e54232SGeorge Liu if (!validChassisPath)
419e4e54232SGeorge Liu {
420bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis",
421bd79bce8SPatrick Williams chassisId);
422e4e54232SGeorge Liu return;
423e4e54232SGeorge Liu }
424bd79bce8SPatrick Williams getValidFanPath(
425bd79bce8SPatrick Williams asyncResp, *validChassisPath, fanId,
426e4e54232SGeorge Liu [asyncResp](const std::string&, const std::string&) {
427e4e54232SGeorge Liu asyncResp->res.addHeader(
428e4e54232SGeorge Liu boost::beast::http::field::link,
429e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby");
430e4e54232SGeorge Liu });
431e4e54232SGeorge Liu });
432e4e54232SGeorge Liu }
433e4e54232SGeorge Liu
handleFanGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & fanId)434e4e54232SGeorge Liu inline void handleFanGet(App& app, const crow::Request& req,
435e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
436e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId)
437e4e54232SGeorge Liu {
438e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp))
439e4e54232SGeorge Liu {
440e4e54232SGeorge Liu return;
441e4e54232SGeorge Liu }
442e4e54232SGeorge Liu
443e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath(
444e4e54232SGeorge Liu asyncResp, chassisId,
445e4e54232SGeorge Liu std::bind_front(doFanGet, asyncResp, chassisId, fanId));
446e4e54232SGeorge Liu }
447e4e54232SGeorge Liu
requestRoutesFan(App & app)448e4e54232SGeorge Liu inline void requestRoutesFan(App& app)
449e4e54232SGeorge Liu {
450e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/")
451e4e54232SGeorge Liu .privileges(redfish::privileges::headFan)
452e4e54232SGeorge Liu .methods(boost::beast::http::verb::head)(
453e4e54232SGeorge Liu std::bind_front(handleFanHead, std::ref(app)));
454e4e54232SGeorge Liu
455e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/")
456e4e54232SGeorge Liu .privileges(redfish::privileges::getFan)
457e4e54232SGeorge Liu .methods(boost::beast::http::verb::get)(
458e4e54232SGeorge Liu std::bind_front(handleFanGet, std::ref(app)));
459e4e54232SGeorge Liu }
460e4e54232SGeorge Liu
4619516f41fSGeorge Liu } // namespace redfish
462