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" 11*1da1ff5fSMyung Bae #include "led.hpp" 12d7857201SEd Tanous #include "logging.hpp" 139516f41fSGeorge Liu #include "query.hpp" 149516f41fSGeorge Liu #include "registries/privilege_registry.hpp" 159516f41fSGeorge Liu #include "utils/chassis_utils.hpp" 16177612aaSEd Tanous #include "utils/dbus_utils.hpp" 17*1da1ff5fSMyung Bae #include "utils/json_utils.hpp" 189516f41fSGeorge Liu 19d7857201SEd Tanous #include <asm-generic/errno.h> 20d7857201SEd Tanous 21d7857201SEd Tanous #include <boost/beast/http/field.hpp> 22d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 239f1ae5aeSAlbert Zhang #include <boost/system/error_code.hpp> 249516f41fSGeorge Liu #include <boost/url/format.hpp> 25d7857201SEd Tanous #include <nlohmann/json.hpp> 26d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp> 279516f41fSGeorge Liu 28d7857201SEd Tanous #include <array> 299516f41fSGeorge Liu #include <functional> 309516f41fSGeorge Liu #include <memory> 319516f41fSGeorge Liu #include <optional> 329516f41fSGeorge Liu #include <string> 339516f41fSGeorge Liu #include <string_view> 34d7857201SEd Tanous #include <utility> 359516f41fSGeorge Liu 369516f41fSGeorge Liu namespace redfish 379516f41fSGeorge Liu { 389516f41fSGeorge Liu constexpr std::array<std::string_view, 1> fanInterface = { 399516f41fSGeorge Liu "xyz.openbmc_project.Inventory.Item.Fan"}; 409516f41fSGeorge Liu 41504af5a0SPatrick Williams inline void updateFanList( 42504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 439516f41fSGeorge Liu const std::string& chassisId, 449516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) 459516f41fSGeorge Liu { 469516f41fSGeorge Liu nlohmann::json& fanList = asyncResp->res.jsonValue["Members"]; 479516f41fSGeorge Liu for (const std::string& fanPath : fanPaths) 489516f41fSGeorge Liu { 499516f41fSGeorge Liu std::string fanName = 509516f41fSGeorge Liu sdbusplus::message::object_path(fanPath).filename(); 519516f41fSGeorge Liu if (fanName.empty()) 529516f41fSGeorge Liu { 539516f41fSGeorge Liu continue; 549516f41fSGeorge Liu } 559516f41fSGeorge Liu 569516f41fSGeorge Liu nlohmann::json item = nlohmann::json::object(); 579516f41fSGeorge Liu item["@odata.id"] = boost::urls::format( 589516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, 599516f41fSGeorge Liu fanName); 609516f41fSGeorge Liu 619516f41fSGeorge Liu fanList.emplace_back(std::move(item)); 629516f41fSGeorge Liu } 639516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = fanList.size(); 649516f41fSGeorge Liu } 659516f41fSGeorge Liu 669516f41fSGeorge Liu inline void getFanPaths( 679516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 68d547d8d2SEd Tanous const std::string& validChassisPath, 699516f41fSGeorge Liu const std::function<void(const dbus::utility::MapperGetSubTreePathsResponse& 709516f41fSGeorge Liu fanPaths)>& callback) 719516f41fSGeorge Liu { 72d547d8d2SEd Tanous sdbusplus::message::object_path endpointPath{validChassisPath}; 739516f41fSGeorge Liu endpointPath /= "cooled_by"; 749516f41fSGeorge Liu 759516f41fSGeorge Liu dbus::utility::getAssociatedSubTreePaths( 769516f41fSGeorge Liu endpointPath, 779516f41fSGeorge Liu sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 789516f41fSGeorge Liu fanInterface, 799516f41fSGeorge Liu [asyncResp, callback]( 809516f41fSGeorge Liu const boost::system::error_code& ec, 819516f41fSGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 829516f41fSGeorge Liu if (ec) 839516f41fSGeorge Liu { 849516f41fSGeorge Liu if (ec.value() != EBADR) 859516f41fSGeorge Liu { 8662598e31SEd Tanous BMCWEB_LOG_ERROR( 8762598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 8862598e31SEd Tanous ec.value()); 899516f41fSGeorge Liu messages::internalError(asyncResp->res); 909516f41fSGeorge Liu } 919516f41fSGeorge Liu return; 929516f41fSGeorge Liu } 939516f41fSGeorge Liu callback(subtreePaths); 949516f41fSGeorge Liu }); 959516f41fSGeorge Liu } 969516f41fSGeorge Liu 979516f41fSGeorge Liu inline void doFanCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 989516f41fSGeorge Liu const std::string& chassisId, 999516f41fSGeorge Liu const std::optional<std::string>& validChassisPath) 1009516f41fSGeorge Liu { 1019516f41fSGeorge Liu if (!validChassisPath) 1029516f41fSGeorge Liu { 1039516f41fSGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 1049516f41fSGeorge Liu return; 1059516f41fSGeorge Liu } 1069516f41fSGeorge Liu 1079516f41fSGeorge Liu asyncResp->res.addHeader( 1089516f41fSGeorge Liu boost::beast::http::field::link, 1099516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); 1109516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.type"] = "#FanCollection.FanCollection"; 1119516f41fSGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1129516f41fSGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans", chassisId); 1139516f41fSGeorge Liu asyncResp->res.jsonValue["Name"] = "Fan Collection"; 1149516f41fSGeorge Liu asyncResp->res.jsonValue["Description"] = 1159516f41fSGeorge Liu "The collection of Fan resource instances " + chassisId; 1169516f41fSGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 1179516f41fSGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 1189516f41fSGeorge Liu 119d547d8d2SEd Tanous getFanPaths(asyncResp, *validChassisPath, 1209516f41fSGeorge Liu std::bind_front(updateFanList, asyncResp, chassisId)); 1219516f41fSGeorge Liu } 1229516f41fSGeorge Liu 123504af5a0SPatrick Williams inline void handleFanCollectionHead( 124504af5a0SPatrick Williams App& app, const crow::Request& req, 1259516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1269516f41fSGeorge Liu const std::string& chassisId) 1279516f41fSGeorge Liu { 1289516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1299516f41fSGeorge Liu { 1309516f41fSGeorge Liu return; 1319516f41fSGeorge Liu } 1329516f41fSGeorge Liu 1339516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath( 1349516f41fSGeorge Liu asyncResp, chassisId, 1359516f41fSGeorge Liu [asyncResp, 1369516f41fSGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 1379516f41fSGeorge Liu if (!validChassisPath) 1389516f41fSGeorge Liu { 139bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 140bd79bce8SPatrick Williams chassisId); 1419516f41fSGeorge Liu return; 1429516f41fSGeorge Liu } 1439516f41fSGeorge Liu asyncResp->res.addHeader( 1449516f41fSGeorge Liu boost::beast::http::field::link, 1459516f41fSGeorge Liu "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); 1469516f41fSGeorge Liu }); 1479516f41fSGeorge Liu } 1489516f41fSGeorge Liu 149504af5a0SPatrick Williams inline void handleFanCollectionGet( 150504af5a0SPatrick Williams App& app, const crow::Request& req, 1519516f41fSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1529516f41fSGeorge Liu const std::string& chassisId) 1539516f41fSGeorge Liu { 1549516f41fSGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1559516f41fSGeorge Liu { 1569516f41fSGeorge Liu return; 1579516f41fSGeorge Liu } 1589516f41fSGeorge Liu 1599516f41fSGeorge Liu redfish::chassis_utils::getValidChassisPath( 1609516f41fSGeorge Liu asyncResp, chassisId, 1619516f41fSGeorge Liu std::bind_front(doFanCollection, asyncResp, chassisId)); 1629516f41fSGeorge Liu } 1639516f41fSGeorge Liu 1649516f41fSGeorge Liu inline void requestRoutesFanCollection(App& app) 1659516f41fSGeorge Liu { 1669516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") 1679516f41fSGeorge Liu .privileges(redfish::privileges::headFanCollection) 1689516f41fSGeorge Liu .methods(boost::beast::http::verb::head)( 1699516f41fSGeorge Liu std::bind_front(handleFanCollectionHead, std::ref(app))); 1709516f41fSGeorge Liu 1719516f41fSGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") 1729516f41fSGeorge Liu .privileges(redfish::privileges::getFanCollection) 1739516f41fSGeorge Liu .methods(boost::beast::http::verb::get)( 1749516f41fSGeorge Liu std::bind_front(handleFanCollectionGet, std::ref(app))); 1759516f41fSGeorge Liu } 1769516f41fSGeorge Liu 177e4e54232SGeorge Liu inline bool checkFanId(const std::string& fanPath, const std::string& fanId) 178e4e54232SGeorge Liu { 179e4e54232SGeorge Liu std::string fanName = sdbusplus::message::object_path(fanPath).filename(); 180e4e54232SGeorge Liu 181e4e54232SGeorge Liu return !(fanName.empty() || fanName != fanId); 182e4e54232SGeorge Liu } 183e4e54232SGeorge Liu 1844ff0f1f4SEd Tanous inline void handleFanPath( 185e4e54232SGeorge Liu const std::string& fanId, 186e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 187e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths, 188e4e54232SGeorge Liu const std::function<void(const std::string& fanPath, 189e4e54232SGeorge Liu const std::string& service)>& callback) 190e4e54232SGeorge Liu { 191e4e54232SGeorge Liu for (const auto& fanPath : fanPaths) 192e4e54232SGeorge Liu { 193e4e54232SGeorge Liu if (!checkFanId(fanPath, fanId)) 194e4e54232SGeorge Liu { 195e4e54232SGeorge Liu continue; 196e4e54232SGeorge Liu } 197e4e54232SGeorge Liu dbus::utility::getDbusObject( 198e4e54232SGeorge Liu fanPath, fanInterface, 199e4e54232SGeorge Liu [fanPath, asyncResp, 200e4e54232SGeorge Liu callback](const boost::system::error_code& ec, 201e4e54232SGeorge Liu const dbus::utility::MapperGetObject& object) { 202e4e54232SGeorge Liu if (ec || object.empty()) 203e4e54232SGeorge Liu { 20462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}", 20562598e31SEd Tanous ec.value()); 206e4e54232SGeorge Liu messages::internalError(asyncResp->res); 207e4e54232SGeorge Liu return; 208e4e54232SGeorge Liu } 209e4e54232SGeorge Liu callback(fanPath, object.begin()->first); 210e4e54232SGeorge Liu }); 211e4e54232SGeorge Liu 212e4e54232SGeorge Liu return; 213e4e54232SGeorge Liu } 21462598e31SEd Tanous BMCWEB_LOG_WARNING("Fan not found {}", fanId); 215e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Fan", fanId); 216e4e54232SGeorge Liu } 217e4e54232SGeorge Liu 218*1da1ff5fSMyung Bae inline void getValidFanObject( 219e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 220e4e54232SGeorge Liu const std::string& validChassisPath, const std::string& fanId, 221e4e54232SGeorge Liu const std::function<void(const std::string& fanPath, 222e4e54232SGeorge Liu const std::string& service)>& callback) 223e4e54232SGeorge Liu { 224e4e54232SGeorge Liu getFanPaths( 225e4e54232SGeorge Liu asyncResp, validChassisPath, 226e4e54232SGeorge Liu [fanId, asyncResp, callback]( 227e4e54232SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) { 228e4e54232SGeorge Liu handleFanPath(fanId, asyncResp, fanPaths, callback); 229e4e54232SGeorge Liu }); 230e4e54232SGeorge Liu } 231e4e54232SGeorge Liu 232e4e54232SGeorge Liu inline void addFanCommonProperties(crow::Response& resp, 233e4e54232SGeorge Liu const std::string& chassisId, 234e4e54232SGeorge Liu const std::string& fanId) 235e4e54232SGeorge Liu { 236e4e54232SGeorge Liu resp.addHeader(boost::beast::http::field::link, 237e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); 238e4e54232SGeorge Liu resp.jsonValue["@odata.type"] = "#Fan.v1_3_0.Fan"; 239e4e54232SGeorge Liu resp.jsonValue["Name"] = "Fan"; 240e4e54232SGeorge Liu resp.jsonValue["Id"] = fanId; 241e4e54232SGeorge Liu resp.jsonValue["@odata.id"] = boost::urls::format( 242e4e54232SGeorge Liu "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, fanId); 243539d8c6bSEd Tanous resp.jsonValue["Status"]["State"] = resource::State::Enabled; 244539d8c6bSEd Tanous resp.jsonValue["Status"]["Health"] = resource::Health::OK; 2459f1ae5aeSAlbert Zhang } 2469f1ae5aeSAlbert Zhang 2479f1ae5aeSAlbert Zhang inline void getFanHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2489f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service) 2499f1ae5aeSAlbert Zhang { 250deae6a78SEd Tanous dbus::utility::getProperty<bool>( 251deae6a78SEd Tanous service, fanPath, 2529f1ae5aeSAlbert Zhang "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 2539f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) { 2549f1ae5aeSAlbert Zhang if (ec) 2559f1ae5aeSAlbert Zhang { 2569f1ae5aeSAlbert Zhang if (ec.value() != EBADR) 2579f1ae5aeSAlbert Zhang { 25862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 25962598e31SEd Tanous ec.value()); 2609f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res); 2619f1ae5aeSAlbert Zhang } 2629f1ae5aeSAlbert Zhang return; 2639f1ae5aeSAlbert Zhang } 2649f1ae5aeSAlbert Zhang 2659f1ae5aeSAlbert Zhang if (!value) 2669f1ae5aeSAlbert Zhang { 267539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 268539d8c6bSEd Tanous resource::Health::Critical; 2699f1ae5aeSAlbert Zhang } 2709f1ae5aeSAlbert Zhang }); 2719f1ae5aeSAlbert Zhang } 2729f1ae5aeSAlbert Zhang 2739f1ae5aeSAlbert Zhang inline void getFanState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2749f1ae5aeSAlbert Zhang const std::string& fanPath, const std::string& service) 2759f1ae5aeSAlbert Zhang { 276deae6a78SEd Tanous dbus::utility::getProperty<bool>( 277deae6a78SEd Tanous service, fanPath, "xyz.openbmc_project.Inventory.Item", "Present", 2789f1ae5aeSAlbert Zhang [asyncResp](const boost::system::error_code& ec, const bool value) { 2799f1ae5aeSAlbert Zhang if (ec) 2809f1ae5aeSAlbert Zhang { 2819f1ae5aeSAlbert Zhang if (ec.value() != EBADR) 2829f1ae5aeSAlbert Zhang { 28362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 28462598e31SEd Tanous ec.value()); 2859f1ae5aeSAlbert Zhang messages::internalError(asyncResp->res); 2869f1ae5aeSAlbert Zhang } 2879f1ae5aeSAlbert Zhang return; 2889f1ae5aeSAlbert Zhang } 2899f1ae5aeSAlbert Zhang 2909f1ae5aeSAlbert Zhang if (!value) 2919f1ae5aeSAlbert Zhang { 292539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 293539d8c6bSEd Tanous resource::State::Absent; 2949f1ae5aeSAlbert Zhang } 2959f1ae5aeSAlbert Zhang }); 296e4e54232SGeorge Liu } 297e4e54232SGeorge Liu 298090ae7baSGeorge Liu inline void getFanAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 299090ae7baSGeorge Liu const std::string& fanPath, const std::string& service) 300090ae7baSGeorge Liu { 301deae6a78SEd Tanous dbus::utility::getAllProperties( 302deae6a78SEd Tanous service, fanPath, "xyz.openbmc_project.Inventory.Decorator.Asset", 303090ae7baSGeorge Liu [fanPath, asyncResp{asyncResp}]( 304090ae7baSGeorge Liu const boost::system::error_code& ec, 305090ae7baSGeorge Liu const dbus::utility::DBusPropertiesMap& assetList) { 306090ae7baSGeorge Liu if (ec) 307090ae7baSGeorge Liu { 308090ae7baSGeorge Liu if (ec.value() != EBADR) 309090ae7baSGeorge Liu { 31062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 31162598e31SEd Tanous ec.value()); 312090ae7baSGeorge Liu messages::internalError(asyncResp->res); 313090ae7baSGeorge Liu } 314090ae7baSGeorge Liu return; 315090ae7baSGeorge Liu } 316090ae7baSGeorge Liu const std::string* manufacturer = nullptr; 317090ae7baSGeorge Liu const std::string* model = nullptr; 318090ae7baSGeorge Liu const std::string* partNumber = nullptr; 319090ae7baSGeorge Liu const std::string* serialNumber = nullptr; 320090ae7baSGeorge Liu const std::string* sparePartNumber = nullptr; 321090ae7baSGeorge Liu 322090ae7baSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 323090ae7baSGeorge Liu dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 324090ae7baSGeorge Liu manufacturer, "Model", model, "PartNumber", partNumber, 325bd79bce8SPatrick Williams "SerialNumber", serialNumber, "SparePartNumber", 326bd79bce8SPatrick Williams sparePartNumber); 327090ae7baSGeorge Liu if (!success) 328090ae7baSGeorge Liu { 329090ae7baSGeorge Liu messages::internalError(asyncResp->res); 330090ae7baSGeorge Liu return; 331090ae7baSGeorge Liu } 332090ae7baSGeorge Liu if (manufacturer != nullptr) 333090ae7baSGeorge Liu { 334090ae7baSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 335090ae7baSGeorge Liu } 336090ae7baSGeorge Liu if (model != nullptr) 337090ae7baSGeorge Liu { 338090ae7baSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 339090ae7baSGeorge Liu } 340090ae7baSGeorge Liu if (partNumber != nullptr) 341090ae7baSGeorge Liu { 342090ae7baSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 343090ae7baSGeorge Liu } 344090ae7baSGeorge Liu if (serialNumber != nullptr) 345090ae7baSGeorge Liu { 346090ae7baSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 347090ae7baSGeorge Liu } 348090ae7baSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 349090ae7baSGeorge Liu { 350090ae7baSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 351090ae7baSGeorge Liu } 352090ae7baSGeorge Liu }); 353090ae7baSGeorge Liu } 354090ae7baSGeorge Liu 355fc3edfddSEd Tanous inline void getFanLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3564a2e485dSGeorge Liu const std::string& fanPath, 3574a2e485dSGeorge Liu const std::string& service) 3584a2e485dSGeorge Liu { 359deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 360deae6a78SEd Tanous service, fanPath, 3614a2e485dSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 362fc3edfddSEd Tanous [asyncResp](const boost::system::error_code& ec, 3634a2e485dSGeorge Liu const std::string& property) { 3644a2e485dSGeorge Liu if (ec) 3654a2e485dSGeorge Liu { 3664a2e485dSGeorge Liu if (ec.value() != EBADR) 3674a2e485dSGeorge Liu { 36862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location{}", 36962598e31SEd Tanous ec.value()); 370fc3edfddSEd Tanous messages::internalError(asyncResp->res); 3714a2e485dSGeorge Liu } 3724a2e485dSGeorge Liu return; 3734a2e485dSGeorge Liu } 374bd79bce8SPatrick Williams asyncResp->res 375bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3764a2e485dSGeorge Liu property; 3774a2e485dSGeorge Liu }); 3784a2e485dSGeorge Liu } 3794a2e485dSGeorge Liu 380*1da1ff5fSMyung Bae inline void afterGetValidFanObject( 381504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 382e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId, 383e4e54232SGeorge Liu const std::string& fanPath, const std::string& service) 384e4e54232SGeorge Liu { 385e4e54232SGeorge Liu addFanCommonProperties(asyncResp->res, chassisId, fanId); 3869f1ae5aeSAlbert Zhang getFanState(asyncResp, fanPath, service); 3879f1ae5aeSAlbert Zhang getFanHealth(asyncResp, fanPath, service); 388090ae7baSGeorge Liu getFanAsset(asyncResp, fanPath, service); 3894a2e485dSGeorge Liu getFanLocation(asyncResp, fanPath, service); 390*1da1ff5fSMyung Bae getLocationIndicatorActive(asyncResp, fanPath); 391e4e54232SGeorge Liu } 392e4e54232SGeorge Liu 393e4e54232SGeorge Liu inline void doFanGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 394e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId, 395e4e54232SGeorge Liu const std::optional<std::string>& validChassisPath) 396e4e54232SGeorge Liu { 397e4e54232SGeorge Liu if (!validChassisPath) 398e4e54232SGeorge Liu { 399e4e54232SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 400e4e54232SGeorge Liu return; 401e4e54232SGeorge Liu } 402e4e54232SGeorge Liu 403*1da1ff5fSMyung Bae getValidFanObject( 404e4e54232SGeorge Liu asyncResp, *validChassisPath, fanId, 405*1da1ff5fSMyung Bae std::bind_front(afterGetValidFanObject, asyncResp, chassisId, fanId)); 406e4e54232SGeorge Liu } 407e4e54232SGeorge Liu 408e4e54232SGeorge Liu inline void handleFanHead(App& app, const crow::Request& req, 409e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 410e4e54232SGeorge Liu const std::string& chassisId, 411e4e54232SGeorge Liu const std::string& fanId) 412e4e54232SGeorge Liu { 413e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 414e4e54232SGeorge Liu { 415e4e54232SGeorge Liu return; 416e4e54232SGeorge Liu } 417e4e54232SGeorge Liu 418e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath( 419e4e54232SGeorge Liu asyncResp, chassisId, 420e4e54232SGeorge Liu [asyncResp, chassisId, 421e4e54232SGeorge Liu fanId](const std::optional<std::string>& validChassisPath) { 422e4e54232SGeorge Liu if (!validChassisPath) 423e4e54232SGeorge Liu { 424bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 425bd79bce8SPatrick Williams chassisId); 426e4e54232SGeorge Liu return; 427e4e54232SGeorge Liu } 428*1da1ff5fSMyung Bae getValidFanObject( 429bd79bce8SPatrick Williams asyncResp, *validChassisPath, fanId, 430e4e54232SGeorge Liu [asyncResp](const std::string&, const std::string&) { 431e4e54232SGeorge Liu asyncResp->res.addHeader( 432e4e54232SGeorge Liu boost::beast::http::field::link, 433e4e54232SGeorge Liu "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); 434e4e54232SGeorge Liu }); 435e4e54232SGeorge Liu }); 436e4e54232SGeorge Liu } 437e4e54232SGeorge Liu 438e4e54232SGeorge Liu inline void handleFanGet(App& app, const crow::Request& req, 439e4e54232SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 440e4e54232SGeorge Liu const std::string& chassisId, const std::string& fanId) 441e4e54232SGeorge Liu { 442e4e54232SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 443e4e54232SGeorge Liu { 444e4e54232SGeorge Liu return; 445e4e54232SGeorge Liu } 446e4e54232SGeorge Liu 447e4e54232SGeorge Liu redfish::chassis_utils::getValidChassisPath( 448e4e54232SGeorge Liu asyncResp, chassisId, 449e4e54232SGeorge Liu std::bind_front(doFanGet, asyncResp, chassisId, fanId)); 450e4e54232SGeorge Liu } 451e4e54232SGeorge Liu 452*1da1ff5fSMyung Bae inline void handleSetFanPathById( 453*1da1ff5fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 454*1da1ff5fSMyung Bae const std::string& chassisId, const std::string& fanId, 455*1da1ff5fSMyung Bae bool locationIndicatorActive, const boost::system::error_code& ec, 456*1da1ff5fSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) 457*1da1ff5fSMyung Bae { 458*1da1ff5fSMyung Bae if (ec) 459*1da1ff5fSMyung Bae { 460*1da1ff5fSMyung Bae if (ec.value() == boost::system::errc::io_error) 461*1da1ff5fSMyung Bae { 462*1da1ff5fSMyung Bae BMCWEB_LOG_WARNING("Chassis {} not found", chassisId); 463*1da1ff5fSMyung Bae messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 464*1da1ff5fSMyung Bae return; 465*1da1ff5fSMyung Bae } 466*1da1ff5fSMyung Bae 467*1da1ff5fSMyung Bae BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 468*1da1ff5fSMyung Bae messages::internalError(asyncResp->res); 469*1da1ff5fSMyung Bae return; 470*1da1ff5fSMyung Bae } 471*1da1ff5fSMyung Bae 472*1da1ff5fSMyung Bae for (const auto& fanPath : fanPaths) 473*1da1ff5fSMyung Bae { 474*1da1ff5fSMyung Bae if (checkFanId(fanPath, fanId)) 475*1da1ff5fSMyung Bae { 476*1da1ff5fSMyung Bae setLocationIndicatorActive(asyncResp, fanPath, 477*1da1ff5fSMyung Bae locationIndicatorActive); 478*1da1ff5fSMyung Bae return; 479*1da1ff5fSMyung Bae } 480*1da1ff5fSMyung Bae } 481*1da1ff5fSMyung Bae BMCWEB_LOG_WARNING("Fan {} not found", fanId); 482*1da1ff5fSMyung Bae messages::resourceNotFound(asyncResp->res, "Fan", fanId); 483*1da1ff5fSMyung Bae } 484*1da1ff5fSMyung Bae 485*1da1ff5fSMyung Bae inline void handleFanPatch(App& app, const crow::Request& req, 486*1da1ff5fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 487*1da1ff5fSMyung Bae const std::string& chassisId, 488*1da1ff5fSMyung Bae const std::string& fanId) 489*1da1ff5fSMyung Bae { 490*1da1ff5fSMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 491*1da1ff5fSMyung Bae { 492*1da1ff5fSMyung Bae return; 493*1da1ff5fSMyung Bae } 494*1da1ff5fSMyung Bae 495*1da1ff5fSMyung Bae std::optional<bool> locationIndicatorActive; 496*1da1ff5fSMyung Bae if (!json_util::readJsonPatch(req, asyncResp->res, 497*1da1ff5fSMyung Bae "LocationIndicatorActive", 498*1da1ff5fSMyung Bae locationIndicatorActive)) 499*1da1ff5fSMyung Bae { 500*1da1ff5fSMyung Bae return; 501*1da1ff5fSMyung Bae } 502*1da1ff5fSMyung Bae 503*1da1ff5fSMyung Bae if (locationIndicatorActive) 504*1da1ff5fSMyung Bae { 505*1da1ff5fSMyung Bae dbus::utility::getAssociatedSubTreePathsById( 506*1da1ff5fSMyung Bae chassisId, "/xyz/openbmc_project/inventory", chassisInterfaces, 507*1da1ff5fSMyung Bae "cooled_by", fanInterface, 508*1da1ff5fSMyung Bae [asyncResp, chassisId, fanId, locationIndicatorActive]( 509*1da1ff5fSMyung Bae const boost::system::error_code& ec, 510*1da1ff5fSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& 511*1da1ff5fSMyung Bae subtreePaths) { 512*1da1ff5fSMyung Bae handleSetFanPathById(asyncResp, chassisId, fanId, 513*1da1ff5fSMyung Bae *locationIndicatorActive, ec, 514*1da1ff5fSMyung Bae subtreePaths); 515*1da1ff5fSMyung Bae }); 516*1da1ff5fSMyung Bae } 517*1da1ff5fSMyung Bae } 518*1da1ff5fSMyung Bae 519e4e54232SGeorge Liu inline void requestRoutesFan(App& app) 520e4e54232SGeorge Liu { 521e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 522e4e54232SGeorge Liu .privileges(redfish::privileges::headFan) 523e4e54232SGeorge Liu .methods(boost::beast::http::verb::head)( 524e4e54232SGeorge Liu std::bind_front(handleFanHead, std::ref(app))); 525e4e54232SGeorge Liu 526e4e54232SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 527e4e54232SGeorge Liu .privileges(redfish::privileges::getFan) 528e4e54232SGeorge Liu .methods(boost::beast::http::verb::get)( 529e4e54232SGeorge Liu std::bind_front(handleFanGet, std::ref(app))); 530*1da1ff5fSMyung Bae 531*1da1ff5fSMyung Bae BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") 532*1da1ff5fSMyung Bae .privileges(redfish::privileges::patchFan) 533*1da1ff5fSMyung Bae .methods(boost::beast::http::verb::patch)( 534*1da1ff5fSMyung Bae std::bind_front(handleFanPatch, std::ref(app))); 535e4e54232SGeorge Liu } 536e4e54232SGeorge Liu 5379516f41fSGeorge Liu } // namespace redfish 538