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" 111da1ff5fSMyung Bae #include "led.hpp" 12d7857201SEd Tanous #include "logging.hpp" 139516f41fSGeorge Liu #include "query.hpp" 149516f41fSGeorge Liu #include "registries/privilege_registry.hpp" 15*f7e62c14SMyung Bae #include "utils/asset_utils.hpp" 169516f41fSGeorge Liu #include "utils/chassis_utils.hpp" 17177612aaSEd Tanous #include "utils/dbus_utils.hpp" 181da1ff5fSMyung Bae #include "utils/json_utils.hpp" 199516f41fSGeorge Liu 20d7857201SEd Tanous #include <asm-generic/errno.h> 21d7857201SEd Tanous 22d7857201SEd Tanous #include <boost/beast/http/field.hpp> 23d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 249f1ae5aeSAlbert Zhang #include <boost/system/error_code.hpp> 259516f41fSGeorge Liu #include <boost/url/format.hpp> 26d7857201SEd Tanous #include <nlohmann/json.hpp> 27d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp> 289516f41fSGeorge Liu 29d7857201SEd Tanous #include <array> 309516f41fSGeorge Liu #include <functional> 319516f41fSGeorge Liu #include <memory> 329516f41fSGeorge Liu #include <optional> 339516f41fSGeorge Liu #include <string> 349516f41fSGeorge Liu #include <string_view> 35d7857201SEd Tanous #include <utility> 369516f41fSGeorge Liu 379516f41fSGeorge Liu namespace redfish 389516f41fSGeorge Liu { 399516f41fSGeorge Liu constexpr std::array<std::string_view, 1> fanInterface = { 409516f41fSGeorge Liu "xyz.openbmc_project.Inventory.Item.Fan"}; 419516f41fSGeorge Liu 42504af5a0SPatrick Williams inline void updateFanList( 43504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 449516f41fSGeorge Liu const std::string& chassisId, 459516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) 469516f41fSGeorge Liu { 479516f41fSGeorge Liu nlohmann::json& fanList = asyncResp->res.jsonValue["Members"]; 489516f41fSGeorge Liu for (const std::string& fanPath : fanPaths) 499516f41fSGeorge Liu { 509516f41fSGeorge Liu std::string fanName = 519516f41fSGeorge Liu sdbusplus::message::object_path(fanPath).filename(); 529516f41fSGeorge Liu if (fanName.empty()) 539516f41fSGeorge Liu { 549516f41fSGeorge Liu continue; 559516f41fSGeorge Liu } 569516f41fSGeorge Liu 579516f41fSGeorge Liu nlohmann::json item = nlohmann::json::object(); 589516f41fSGeorge Liu item["@odata.id"] = boost::urls::format( 599516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, 609516f41fSGeorge Liu fanName); 619516f41fSGeorge Liu 629516f41fSGeorge Liu fanList.emplace_back(std::move(item)); 639516f41fSGeorge Liu } 649516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = fanList.size(); 659516f41fSGeorge Liu } 669516f41fSGeorge Liu 679516f41fSGeorge Liu inline void getFanPaths( 689516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 69d547d8d2SEd Tanous const std::string& validChassisPath, 709516f41fSGeorge Liu const std::function<void(const dbus::utility::MapperGetSubTreePathsResponse& 719516f41fSGeorge Liu fanPaths)>& callback) 729516f41fSGeorge Liu { 73d547d8d2SEd Tanous sdbusplus::message::object_path endpointPath{validChassisPath}; 749516f41fSGeorge Liu endpointPath /= "cooled_by"; 759516f41fSGeorge Liu 769516f41fSGeorge Liu dbus::utility::getAssociatedSubTreePaths( 779516f41fSGeorge Liu endpointPath, 789516f41fSGeorge Liu sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 799516f41fSGeorge Liu fanInterface, 809516f41fSGeorge Liu [asyncResp, callback]( 819516f41fSGeorge Liu const boost::system::error_code& ec, 829516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 839516f41fSGeorge Liu if (ec) 849516f41fSGeorge Liu { 859516f41fSGeorge Liu if (ec.value() != EBADR) 869516f41fSGeorge Liu { 8762598e31SEd Tanous BMCWEB_LOG_ERROR( 8862598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 8962598e31SEd Tanous ec.value()); 909516f41fSGeorge Liu messages::internalError(asyncResp->res); 919516f41fSGeorge Liu } 929516f41fSGeorge Liu return; 939516f41fSGeorge Liu } 949516f41fSGeorge Liu callback(subtreePaths); 959516f41fSGeorge Liu }); 969516f41fSGeorge Liu } 979516f41fSGeorge Liu 989516f41fSGeorge Liu inline void doFanCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 999516f41fSGeorge Liu const std::string& chassisId, 1009516f41fSGeorge Liu const std::optional<std::string>& validChassisPath) 1019516f41fSGeorge Liu { 1029516f41fSGeorge Liu if (!validChassisPath) 1039516f41fSGeorge Liu { 1049516f41fSGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 1059516f41fSGeorge Liu return; 1069516f41fSGeorge Liu } 1079516f41fSGeorge Liu 1089516f41fSGeorge Liu asyncResp->res.addHeader( 1099516f41fSGeorge Liu boost::beast::http::field::link, 1109516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); 1119516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.type"] = "#FanCollection.FanCollection"; 1129516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1139516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans", chassisId); 1149516f41fSGeorge Liu asyncResp->res.jsonValue["Name"] = "Fan Collection"; 1159516f41fSGeorge Liu asyncResp->res.jsonValue["Description"] = 1169516f41fSGeorge Liu "The collection of Fan resource instances " + chassisId; 1179516f41fSGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 1189516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 1199516f41fSGeorge Liu 120d547d8d2SEd Tanous getFanPaths(asyncResp, *validChassisPath, 1219516f41fSGeorge Liu std::bind_front(updateFanList, asyncResp, chassisId)); 1229516f41fSGeorge Liu } 1239516f41fSGeorge Liu 124504af5a0SPatrick Williams inline void handleFanCollectionHead( 125504af5a0SPatrick Williams App& app, const crow::Request& req, 1269516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1279516f41fSGeorge Liu const std::string& chassisId) 1289516f41fSGeorge Liu { 1299516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1309516f41fSGeorge Liu { 1319516f41fSGeorge Liu return; 1329516f41fSGeorge Liu } 1339516f41fSGeorge Liu 1349516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath( 1359516f41fSGeorge Liu asyncResp, chassisId, 1369516f41fSGeorge Liu [asyncResp, 1379516f41fSGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 1389516f41fSGeorge Liu if (!validChassisPath) 1399516f41fSGeorge Liu { 140bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 141bd79bce8SPatrick Williams chassisId); 1429516f41fSGeorge Liu return; 1439516f41fSGeorge Liu } 1449516f41fSGeorge Liu asyncResp->res.addHeader( 1459516f41fSGeorge Liu boost::beast::http::field::link, 1469516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); 1479516f41fSGeorge Liu }); 1489516f41fSGeorge Liu } 1499516f41fSGeorge Liu 150504af5a0SPatrick Williams inline void handleFanCollectionGet( 151504af5a0SPatrick Williams App& app, const crow::Request& req, 1529516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1539516f41fSGeorge Liu const std::string& chassisId) 1549516f41fSGeorge Liu { 1559516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1569516f41fSGeorge Liu { 1579516f41fSGeorge Liu return; 1589516f41fSGeorge Liu } 1599516f41fSGeorge Liu 1609516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath( 1619516f41fSGeorge Liu asyncResp, chassisId, 1629516f41fSGeorge Liu std::bind_front(doFanCollection, asyncResp, chassisId)); 1639516f41fSGeorge Liu } 1649516f41fSGeorge Liu 1659516f41fSGeorge Liu inline void requestRoutesFanCollection(App& app) 1669516f41fSGeorge Liu { 1679516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") 1689516f41fSGeorge Liu .privileges(redfish::privileges::headFanCollection) 1699516f41fSGeorge Liu .methods(boost::beast::http::verb::head)( 1709516f41fSGeorge Liu std::bind_front(handleFanCollectionHead, std::ref(app))); 1719516f41fSGeorge Liu 1729516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") 1739516f41fSGeorge Liu .privileges(redfish::privileges::getFanCollection) 1749516f41fSGeorge Liu .methods(boost::beast::http::verb::get)( 1759516f41fSGeorge Liu std::bind_front(handleFanCollectionGet, std::ref(app))); 1769516f41fSGeorge Liu } 1779516f41fSGeorge Liu 178e4e54232SGeorge Liu inline bool checkFanId(const std::string& fanPath, const std::string& fanId) 179e4e54232SGeorge Liu { 180e4e54232SGeorge Liu std::string fanName = sdbusplus::message::object_path(fanPath).filename(); 181e4e54232SGeorge Liu 182e4e54232SGeorge Liu return !(fanName.empty() || fanName != fanId); 183e4e54232SGeorge Liu } 184e4e54232SGeorge Liu 1854ff0f1f4SEd Tanous inline void handleFanPath( 186e4e54232SGeorge Liu const std::string& fanId, 187e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 188e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths, 189e4e54232SGeorge Liu const std::function<void(const std::string& fanPath, 190e4e54232SGeorge Liu const std::string& service)>& callback) 191e4e54232SGeorge Liu { 192e4e54232SGeorge Liu for (const auto& fanPath : fanPaths) 193e4e54232SGeorge Liu { 194e4e54232SGeorge Liu if (!checkFanId(fanPath, fanId)) 195e4e54232SGeorge Liu { 196e4e54232SGeorge Liu continue; 197e4e54232SGeorge Liu } 198e4e54232SGeorge Liu dbus::utility::getDbusObject( 199e4e54232SGeorge Liu fanPath, fanInterface, 200e4e54232SGeorge Liu [fanPath, asyncResp, 201e4e54232SGeorge Liu callback](const boost::system::error_code& ec, 202e4e54232SGeorge Liu const dbus::utility::MapperGetObject& object) { 203e4e54232SGeorge Liu if (ec || object.empty()) 204e4e54232SGeorge Liu { 20562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}", 20662598e31SEd Tanous ec.value()); 207e4e54232SGeorge Liu messages::internalError(asyncResp->res); 208e4e54232SGeorge Liu return; 209e4e54232SGeorge Liu } 210e4e54232SGeorge Liu callback(fanPath, object.begin()->first); 211e4e54232SGeorge Liu }); 212e4e54232SGeorge Liu 213e4e54232SGeorge Liu return; 214e4e54232SGeorge Liu } 21562598e31SEd Tanous BMCWEB_LOG_WARNING("Fan not found {}", fanId); 216e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Fan", fanId); 217e4e54232SGeorge Liu } 218e4e54232SGeorge Liu 2191da1ff5fSMyung Bae inline void getValidFanObject( 220e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 221e4e54232SGeorge Liu const std::string& validChassisPath, const std::string& fanId, 222e4e54232SGeorge Liu const std::function<void(const std::string& fanPath, 223e4e54232SGeorge Liu const std::string& service)>& callback) 224e4e54232SGeorge Liu { 225e4e54232SGeorge Liu getFanPaths( 226e4e54232SGeorge Liu asyncResp, validChassisPath, 227e4e54232SGeorge Liu [fanId, asyncResp, callback]( 228e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) { 229e4e54232SGeorge Liu handleFanPath(fanId, asyncResp, fanPaths, callback); 230e4e54232SGeorge Liu }); 231e4e54232SGeorge Liu } 232e4e54232SGeorge Liu 233e4e54232SGeorge Liu inline void addFanCommonProperties(crow::Response& resp, 234e4e54232SGeorge Liu const std::string& chassisId, 235e4e54232SGeorge Liu const std::string& fanId) 236e4e54232SGeorge Liu { 237e4e54232SGeorge Liu resp.addHeader(boost::beast::http::field::link, 238e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); 239e4e54232SGeorge Liu resp.jsonValue["@odata.type"] = "#Fan.v1_3_0.Fan"; 240e4e54232SGeorge Liu resp.jsonValue["Name"] = "Fan"; 241e4e54232SGeorge Liu resp.jsonValue["Id"] = fanId; 242e4e54232SGeorge Liu resp.jsonValue["@odata.id"] = boost::urls::format( 243e4e54232SGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, fanId); 244539d8c6bSEd Tanous resp.jsonValue["Status"]["State"] = resource::State::Enabled; 245539d8c6bSEd Tanous resp.jsonValue["Status"]["Health"] = resource::Health::OK; 2469f1ae5aeSAlbert Zhang } 2479f1ae5aeSAlbert Zhang 2489f1ae5aeSAlbert Zhang inline void getFanHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2499f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service) 2509f1ae5aeSAlbert Zhang { 251deae6a78SEd Tanous dbus::utility::getProperty<bool>( 252deae6a78SEd Tanous service, fanPath, 2539f1ae5aeSAlbert Zhang "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 2549f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) { 2559f1ae5aeSAlbert Zhang if (ec) 2569f1ae5aeSAlbert Zhang { 2579f1ae5aeSAlbert Zhang if (ec.value() != EBADR) 2589f1ae5aeSAlbert Zhang { 25962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 26062598e31SEd Tanous ec.value()); 2619f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res); 2629f1ae5aeSAlbert Zhang } 2639f1ae5aeSAlbert Zhang return; 2649f1ae5aeSAlbert Zhang } 2659f1ae5aeSAlbert Zhang 2669f1ae5aeSAlbert Zhang if (!value) 2679f1ae5aeSAlbert Zhang { 268539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 269539d8c6bSEd Tanous resource::Health::Critical; 2709f1ae5aeSAlbert Zhang } 2719f1ae5aeSAlbert Zhang }); 2729f1ae5aeSAlbert Zhang } 2739f1ae5aeSAlbert Zhang 2749f1ae5aeSAlbert Zhang inline void getFanState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2759f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service) 2769f1ae5aeSAlbert Zhang { 277deae6a78SEd Tanous dbus::utility::getProperty<bool>( 278deae6a78SEd Tanous service, fanPath, "xyz.openbmc_project.Inventory.Item", "Present", 2799f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) { 2809f1ae5aeSAlbert Zhang if (ec) 2819f1ae5aeSAlbert Zhang { 2829f1ae5aeSAlbert Zhang if (ec.value() != EBADR) 2839f1ae5aeSAlbert Zhang { 28462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 28562598e31SEd Tanous ec.value()); 2869f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res); 2879f1ae5aeSAlbert Zhang } 2889f1ae5aeSAlbert Zhang return; 2899f1ae5aeSAlbert Zhang } 2909f1ae5aeSAlbert Zhang 2919f1ae5aeSAlbert Zhang if (!value) 2929f1ae5aeSAlbert Zhang { 293539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 294539d8c6bSEd Tanous resource::State::Absent; 2959f1ae5aeSAlbert Zhang } 2969f1ae5aeSAlbert Zhang }); 297e4e54232SGeorge Liu } 298e4e54232SGeorge Liu 299fc3edfddSEd Tanous inline void getFanLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3004a2e485dSGeorge Liu const std::string& fanPath, 3014a2e485dSGeorge Liu const std::string& service) 3024a2e485dSGeorge Liu { 303deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 304deae6a78SEd Tanous service, fanPath, 3054a2e485dSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 306fc3edfddSEd Tanous [asyncResp](const boost::system::error_code& ec, 3074a2e485dSGeorge Liu const std::string& property) { 3084a2e485dSGeorge Liu if (ec) 3094a2e485dSGeorge Liu { 3104a2e485dSGeorge Liu if (ec.value() != EBADR) 3114a2e485dSGeorge Liu { 31262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location{}", 31362598e31SEd Tanous ec.value()); 314fc3edfddSEd Tanous messages::internalError(asyncResp->res); 3154a2e485dSGeorge Liu } 3164a2e485dSGeorge Liu return; 3174a2e485dSGeorge Liu } 318bd79bce8SPatrick Williams asyncResp->res 319bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3204a2e485dSGeorge Liu property; 3214a2e485dSGeorge Liu }); 3224a2e485dSGeorge Liu } 3234a2e485dSGeorge Liu 3241da1ff5fSMyung Bae inline void afterGetValidFanObject( 325504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 326e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId, 327e4e54232SGeorge Liu const std::string& fanPath, const std::string& service) 328e4e54232SGeorge Liu { 329e4e54232SGeorge Liu addFanCommonProperties(asyncResp->res, chassisId, fanId); 3309f1ae5aeSAlbert Zhang getFanState(asyncResp, fanPath, service); 3319f1ae5aeSAlbert Zhang getFanHealth(asyncResp, fanPath, service); 332*f7e62c14SMyung Bae asset_utils::getAssetInfo(asyncResp, service, fanPath, ""_json_pointer, 333*f7e62c14SMyung Bae true); 3344a2e485dSGeorge Liu getFanLocation(asyncResp, fanPath, service); 3351da1ff5fSMyung Bae getLocationIndicatorActive(asyncResp, fanPath); 336e4e54232SGeorge Liu } 337e4e54232SGeorge Liu 338e4e54232SGeorge Liu inline void doFanGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 339e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId, 340e4e54232SGeorge Liu const std::optional<std::string>& validChassisPath) 341e4e54232SGeorge Liu { 342e4e54232SGeorge Liu if (!validChassisPath) 343e4e54232SGeorge Liu { 344e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 345e4e54232SGeorge Liu return; 346e4e54232SGeorge Liu } 347e4e54232SGeorge Liu 3481da1ff5fSMyung Bae getValidFanObject( 349e4e54232SGeorge Liu asyncResp, *validChassisPath, fanId, 3501da1ff5fSMyung Bae std::bind_front(afterGetValidFanObject, asyncResp, chassisId, fanId)); 351e4e54232SGeorge Liu } 352e4e54232SGeorge Liu 353e4e54232SGeorge Liu inline void handleFanHead(App& app, const crow::Request& req, 354e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 355e4e54232SGeorge Liu const std::string& chassisId, 356e4e54232SGeorge Liu const std::string& fanId) 357e4e54232SGeorge Liu { 358e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 359e4e54232SGeorge Liu { 360e4e54232SGeorge Liu return; 361e4e54232SGeorge Liu } 362e4e54232SGeorge Liu 363e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath( 364e4e54232SGeorge Liu asyncResp, chassisId, 365e4e54232SGeorge Liu [asyncResp, chassisId, 366e4e54232SGeorge Liu fanId](const std::optional<std::string>& validChassisPath) { 367e4e54232SGeorge Liu if (!validChassisPath) 368e4e54232SGeorge Liu { 369bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 370bd79bce8SPatrick Williams chassisId); 371e4e54232SGeorge Liu return; 372e4e54232SGeorge Liu } 3731da1ff5fSMyung Bae getValidFanObject( 374bd79bce8SPatrick Williams asyncResp, *validChassisPath, fanId, 375e4e54232SGeorge Liu [asyncResp](const std::string&, const std::string&) { 376e4e54232SGeorge Liu asyncResp->res.addHeader( 377e4e54232SGeorge Liu boost::beast::http::field::link, 378e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); 379e4e54232SGeorge Liu }); 380e4e54232SGeorge Liu }); 381e4e54232SGeorge Liu } 382e4e54232SGeorge Liu 383e4e54232SGeorge Liu inline void handleFanGet(App& app, const crow::Request& req, 384e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 385e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId) 386e4e54232SGeorge Liu { 387e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 388e4e54232SGeorge Liu { 389e4e54232SGeorge Liu return; 390e4e54232SGeorge Liu } 391e4e54232SGeorge Liu 392e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath( 393e4e54232SGeorge Liu asyncResp, chassisId, 394e4e54232SGeorge Liu std::bind_front(doFanGet, asyncResp, chassisId, fanId)); 395e4e54232SGeorge Liu } 396e4e54232SGeorge Liu 3971da1ff5fSMyung Bae inline void handleSetFanPathById( 3981da1ff5fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3991da1ff5fSMyung Bae const std::string& chassisId, const std::string& fanId, 4001da1ff5fSMyung Bae bool locationIndicatorActive, const boost::system::error_code& ec, 4011da1ff5fSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) 4021da1ff5fSMyung Bae { 4031da1ff5fSMyung Bae if (ec) 4041da1ff5fSMyung Bae { 4051da1ff5fSMyung Bae if (ec.value() == boost::system::errc::io_error) 4061da1ff5fSMyung Bae { 4071da1ff5fSMyung Bae BMCWEB_LOG_WARNING("Chassis {} not found", chassisId); 4081da1ff5fSMyung Bae messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 4091da1ff5fSMyung Bae return; 4101da1ff5fSMyung Bae } 4111da1ff5fSMyung Bae 4121da1ff5fSMyung Bae BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 4131da1ff5fSMyung Bae messages::internalError(asyncResp->res); 4141da1ff5fSMyung Bae return; 4151da1ff5fSMyung Bae } 4161da1ff5fSMyung Bae 4171da1ff5fSMyung Bae for (const auto& fanPath : fanPaths) 4181da1ff5fSMyung Bae { 4191da1ff5fSMyung Bae if (checkFanId(fanPath, fanId)) 4201da1ff5fSMyung Bae { 4211da1ff5fSMyung Bae setLocationIndicatorActive(asyncResp, fanPath, 4221da1ff5fSMyung Bae locationIndicatorActive); 4231da1ff5fSMyung Bae return; 4241da1ff5fSMyung Bae } 4251da1ff5fSMyung Bae } 4261da1ff5fSMyung Bae BMCWEB_LOG_WARNING("Fan {} not found", fanId); 4271da1ff5fSMyung Bae messages::resourceNotFound(asyncResp->res, "Fan", fanId); 4281da1ff5fSMyung Bae } 4291da1ff5fSMyung Bae 4301da1ff5fSMyung Bae inline void handleFanPatch(App& app, const crow::Request& req, 4311da1ff5fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4321da1ff5fSMyung Bae const std::string& chassisId, 4331da1ff5fSMyung Bae const std::string& fanId) 4341da1ff5fSMyung Bae { 4351da1ff5fSMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 4361da1ff5fSMyung Bae { 4371da1ff5fSMyung Bae return; 4381da1ff5fSMyung Bae } 4391da1ff5fSMyung Bae 4401da1ff5fSMyung Bae std::optional<bool> locationIndicatorActive; 4411da1ff5fSMyung Bae if (!json_util::readJsonPatch(req, asyncResp->res, 4421da1ff5fSMyung Bae "LocationIndicatorActive", 4431da1ff5fSMyung Bae locationIndicatorActive)) 4441da1ff5fSMyung Bae { 4451da1ff5fSMyung Bae return; 4461da1ff5fSMyung Bae } 4471da1ff5fSMyung Bae 4481da1ff5fSMyung Bae if (locationIndicatorActive) 4491da1ff5fSMyung Bae { 4501da1ff5fSMyung Bae dbus::utility::getAssociatedSubTreePathsById( 4511da1ff5fSMyung Bae chassisId, "/xyz/openbmc_project/inventory", chassisInterfaces, 4521da1ff5fSMyung Bae "cooled_by", fanInterface, 4531da1ff5fSMyung Bae [asyncResp, chassisId, fanId, locationIndicatorActive]( 4541da1ff5fSMyung Bae const boost::system::error_code& ec, 4551da1ff5fSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& 4561da1ff5fSMyung Bae subtreePaths) { 4571da1ff5fSMyung Bae handleSetFanPathById(asyncResp, chassisId, fanId, 4581da1ff5fSMyung Bae *locationIndicatorActive, ec, 4591da1ff5fSMyung Bae subtreePaths); 4601da1ff5fSMyung Bae }); 4611da1ff5fSMyung Bae } 4621da1ff5fSMyung Bae } 4631da1ff5fSMyung Bae 464e4e54232SGeorge Liu inline void requestRoutesFan(App& app) 465e4e54232SGeorge Liu { 466e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 467e4e54232SGeorge Liu .privileges(redfish::privileges::headFan) 468e4e54232SGeorge Liu .methods(boost::beast::http::verb::head)( 469e4e54232SGeorge Liu std::bind_front(handleFanHead, std::ref(app))); 470e4e54232SGeorge Liu 471e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 472e4e54232SGeorge Liu .privileges(redfish::privileges::getFan) 473e4e54232SGeorge Liu .methods(boost::beast::http::verb::get)( 474e4e54232SGeorge Liu std::bind_front(handleFanGet, std::ref(app))); 4751da1ff5fSMyung Bae 4761da1ff5fSMyung Bae BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 4771da1ff5fSMyung Bae .privileges(redfish::privileges::patchFan) 4781da1ff5fSMyung Bae .methods(boost::beast::http::verb::patch)( 4791da1ff5fSMyung Bae std::bind_front(handleFanPatch, std::ref(app))); 480e4e54232SGeorge Liu } 481e4e54232SGeorge Liu 4829516f41fSGeorge Liu } // namespace redfish 483