| Ed Tanous | 40e9b92 | 2024-09-10 13:50:16 -0700 | [diff] [blame^] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
|  | 2 | // SPDX-FileCopyrightText: Copyright OpenBMC Authors | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 3 | #pragma once | 
|  | 4 |  | 
|  | 5 | #include "app.hpp" | 
|  | 6 | #include "dbus_utility.hpp" | 
|  | 7 | #include "error_messages.hpp" | 
| Ed Tanous | 539d8c6 | 2024-06-19 14:38:27 -0700 | [diff] [blame] | 8 | #include "generated/enums/resource.hpp" | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 9 | #include "query.hpp" | 
|  | 10 | #include "registries/privilege_registry.hpp" | 
|  | 11 | #include "utils/chassis_utils.hpp" | 
|  | 12 |  | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 13 | #include <boost/system/error_code.hpp> | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 14 | #include <boost/url/format.hpp> | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 15 | #include <sdbusplus/asio/property.hpp> | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 16 | #include <sdbusplus/message/types.hpp> | 
|  | 17 |  | 
|  | 18 | #include <functional> | 
|  | 19 | #include <memory> | 
|  | 20 | #include <optional> | 
|  | 21 | #include <string> | 
|  | 22 | #include <string_view> | 
|  | 23 |  | 
|  | 24 | namespace redfish | 
|  | 25 | { | 
|  | 26 | constexpr std::array<std::string_view, 1> fanInterface = { | 
|  | 27 | "xyz.openbmc_project.Inventory.Item.Fan"}; | 
|  | 28 |  | 
|  | 29 | inline void | 
|  | 30 | updateFanList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 31 | const std::string& chassisId, | 
|  | 32 | const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) | 
|  | 33 | { | 
|  | 34 | nlohmann::json& fanList = asyncResp->res.jsonValue["Members"]; | 
|  | 35 | for (const std::string& fanPath : fanPaths) | 
|  | 36 | { | 
|  | 37 | std::string fanName = | 
|  | 38 | sdbusplus::message::object_path(fanPath).filename(); | 
|  | 39 | if (fanName.empty()) | 
|  | 40 | { | 
|  | 41 | continue; | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | nlohmann::json item = nlohmann::json::object(); | 
|  | 45 | item["@odata.id"] = boost::urls::format( | 
|  | 46 | "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, | 
|  | 47 | fanName); | 
|  | 48 |  | 
|  | 49 | fanList.emplace_back(std::move(item)); | 
|  | 50 | } | 
|  | 51 | asyncResp->res.jsonValue["Members@odata.count"] = fanList.size(); | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | inline void getFanPaths( | 
|  | 55 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
| Ed Tanous | d547d8d | 2024-03-16 18:04:41 -0700 | [diff] [blame] | 56 | const std::string& validChassisPath, | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 57 | const std::function<void(const dbus::utility::MapperGetSubTreePathsResponse& | 
|  | 58 | fanPaths)>& callback) | 
|  | 59 | { | 
| Ed Tanous | d547d8d | 2024-03-16 18:04:41 -0700 | [diff] [blame] | 60 | sdbusplus::message::object_path endpointPath{validChassisPath}; | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 61 | endpointPath /= "cooled_by"; | 
|  | 62 |  | 
|  | 63 | dbus::utility::getAssociatedSubTreePaths( | 
|  | 64 | endpointPath, | 
|  | 65 | sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, | 
|  | 66 | fanInterface, | 
|  | 67 | [asyncResp, callback]( | 
|  | 68 | const boost::system::error_code& ec, | 
|  | 69 | const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 70 | if (ec) | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 71 | { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 72 | if (ec.value() != EBADR) | 
|  | 73 | { | 
|  | 74 | BMCWEB_LOG_ERROR( | 
|  | 75 | "DBUS response error for getAssociatedSubTreePaths {}", | 
|  | 76 | ec.value()); | 
|  | 77 | messages::internalError(asyncResp->res); | 
|  | 78 | } | 
|  | 79 | return; | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 80 | } | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 81 | callback(subtreePaths); | 
|  | 82 | }); | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 83 | } | 
|  | 84 |  | 
|  | 85 | inline void doFanCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 86 | const std::string& chassisId, | 
|  | 87 | const std::optional<std::string>& validChassisPath) | 
|  | 88 | { | 
|  | 89 | if (!validChassisPath) | 
|  | 90 | { | 
|  | 91 | messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); | 
|  | 92 | return; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | asyncResp->res.addHeader( | 
|  | 96 | boost::beast::http::field::link, | 
|  | 97 | "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); | 
|  | 98 | asyncResp->res.jsonValue["@odata.type"] = "#FanCollection.FanCollection"; | 
|  | 99 | asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( | 
|  | 100 | "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans", chassisId); | 
|  | 101 | asyncResp->res.jsonValue["Name"] = "Fan Collection"; | 
|  | 102 | asyncResp->res.jsonValue["Description"] = | 
|  | 103 | "The collection of Fan resource instances " + chassisId; | 
|  | 104 | asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); | 
|  | 105 | asyncResp->res.jsonValue["Members@odata.count"] = 0; | 
|  | 106 |  | 
| Ed Tanous | d547d8d | 2024-03-16 18:04:41 -0700 | [diff] [blame] | 107 | getFanPaths(asyncResp, *validChassisPath, | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 108 | std::bind_front(updateFanList, asyncResp, chassisId)); | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | inline void | 
|  | 112 | handleFanCollectionHead(App& app, const crow::Request& req, | 
|  | 113 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 114 | const std::string& chassisId) | 
|  | 115 | { | 
|  | 116 | if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
|  | 117 | { | 
|  | 118 | return; | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | redfish::chassis_utils::getValidChassisPath( | 
|  | 122 | asyncResp, chassisId, | 
|  | 123 | [asyncResp, | 
|  | 124 | chassisId](const std::optional<std::string>& validChassisPath) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 125 | if (!validChassisPath) | 
|  | 126 | { | 
|  | 127 | messages::resourceNotFound(asyncResp->res, "Chassis", | 
|  | 128 | chassisId); | 
|  | 129 | return; | 
|  | 130 | } | 
|  | 131 | asyncResp->res.addHeader( | 
|  | 132 | boost::beast::http::field::link, | 
|  | 133 | "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby"); | 
|  | 134 | }); | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 135 | } | 
|  | 136 |  | 
|  | 137 | inline void | 
|  | 138 | handleFanCollectionGet(App& app, const crow::Request& req, | 
|  | 139 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 140 | const std::string& chassisId) | 
|  | 141 | { | 
|  | 142 | if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
|  | 143 | { | 
|  | 144 | return; | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | redfish::chassis_utils::getValidChassisPath( | 
|  | 148 | asyncResp, chassisId, | 
|  | 149 | std::bind_front(doFanCollection, asyncResp, chassisId)); | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | inline void requestRoutesFanCollection(App& app) | 
|  | 153 | { | 
|  | 154 | BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") | 
|  | 155 | .privileges(redfish::privileges::headFanCollection) | 
|  | 156 | .methods(boost::beast::http::verb::head)( | 
|  | 157 | std::bind_front(handleFanCollectionHead, std::ref(app))); | 
|  | 158 |  | 
|  | 159 | BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/") | 
|  | 160 | .privileges(redfish::privileges::getFanCollection) | 
|  | 161 | .methods(boost::beast::http::verb::get)( | 
|  | 162 | std::bind_front(handleFanCollectionGet, std::ref(app))); | 
|  | 163 | } | 
|  | 164 |  | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 165 | inline bool checkFanId(const std::string& fanPath, const std::string& fanId) | 
|  | 166 | { | 
|  | 167 | std::string fanName = sdbusplus::message::object_path(fanPath).filename(); | 
|  | 168 |  | 
|  | 169 | return !(fanName.empty() || fanName != fanId); | 
|  | 170 | } | 
|  | 171 |  | 
| Ed Tanous | 4ff0f1f | 2024-09-04 17:27:37 -0700 | [diff] [blame] | 172 | inline void handleFanPath( | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 173 | const std::string& fanId, | 
|  | 174 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 175 | const dbus::utility::MapperGetSubTreePathsResponse& fanPaths, | 
|  | 176 | const std::function<void(const std::string& fanPath, | 
|  | 177 | const std::string& service)>& callback) | 
|  | 178 | { | 
|  | 179 | for (const auto& fanPath : fanPaths) | 
|  | 180 | { | 
|  | 181 | if (!checkFanId(fanPath, fanId)) | 
|  | 182 | { | 
|  | 183 | continue; | 
|  | 184 | } | 
|  | 185 | dbus::utility::getDbusObject( | 
|  | 186 | fanPath, fanInterface, | 
|  | 187 | [fanPath, asyncResp, | 
|  | 188 | callback](const boost::system::error_code& ec, | 
|  | 189 | const dbus::utility::MapperGetObject& object) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 190 | if (ec || object.empty()) | 
|  | 191 | { | 
|  | 192 | BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}", | 
|  | 193 | ec.value()); | 
|  | 194 | messages::internalError(asyncResp->res); | 
|  | 195 | return; | 
|  | 196 | } | 
|  | 197 | callback(fanPath, object.begin()->first); | 
|  | 198 | }); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 199 |  | 
|  | 200 | return; | 
|  | 201 | } | 
| Ed Tanous | 62598e3 | 2023-07-17 17:06:25 -0700 | [diff] [blame] | 202 | BMCWEB_LOG_WARNING("Fan not found {}", fanId); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 203 | messages::resourceNotFound(asyncResp->res, "Fan", fanId); | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | inline void getValidFanPath( | 
|  | 207 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 208 | const std::string& validChassisPath, const std::string& fanId, | 
|  | 209 | const std::function<void(const std::string& fanPath, | 
|  | 210 | const std::string& service)>& callback) | 
|  | 211 | { | 
|  | 212 | getFanPaths( | 
|  | 213 | asyncResp, validChassisPath, | 
|  | 214 | [fanId, asyncResp, callback]( | 
|  | 215 | const dbus::utility::MapperGetSubTreePathsResponse& fanPaths) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 216 | handleFanPath(fanId, asyncResp, fanPaths, callback); | 
|  | 217 | }); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 218 | } | 
|  | 219 |  | 
|  | 220 | inline void addFanCommonProperties(crow::Response& resp, | 
|  | 221 | const std::string& chassisId, | 
|  | 222 | const std::string& fanId) | 
|  | 223 | { | 
|  | 224 | resp.addHeader(boost::beast::http::field::link, | 
|  | 225 | "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); | 
|  | 226 | resp.jsonValue["@odata.type"] = "#Fan.v1_3_0.Fan"; | 
|  | 227 | resp.jsonValue["Name"] = "Fan"; | 
|  | 228 | resp.jsonValue["Id"] = fanId; | 
|  | 229 | resp.jsonValue["@odata.id"] = boost::urls::format( | 
|  | 230 | "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId, fanId); | 
| Ed Tanous | 539d8c6 | 2024-06-19 14:38:27 -0700 | [diff] [blame] | 231 | resp.jsonValue["Status"]["State"] = resource::State::Enabled; | 
|  | 232 | resp.jsonValue["Status"]["Health"] = resource::Health::OK; | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
|  | 235 | inline void getFanHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 236 | const std::string& fanPath, const std::string& service) | 
|  | 237 | { | 
| Ed Tanous | deae6a7 | 2024-11-11 21:58:57 -0800 | [diff] [blame] | 238 | dbus::utility::getProperty<bool>( | 
|  | 239 | service, fanPath, | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 240 | "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", | 
|  | 241 | [asyncResp](const boost::system::error_code& ec, const bool value) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 242 | if (ec) | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 243 | { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 244 | if (ec.value() != EBADR) | 
|  | 245 | { | 
|  | 246 | BMCWEB_LOG_ERROR("DBUS response error for Health {}", | 
|  | 247 | ec.value()); | 
|  | 248 | messages::internalError(asyncResp->res); | 
|  | 249 | } | 
|  | 250 | return; | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 251 | } | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 252 |  | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 253 | if (!value) | 
|  | 254 | { | 
|  | 255 | asyncResp->res.jsonValue["Status"]["Health"] = | 
|  | 256 | resource::Health::Critical; | 
|  | 257 | } | 
|  | 258 | }); | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 259 | } | 
|  | 260 |  | 
|  | 261 | inline void getFanState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 262 | const std::string& fanPath, const std::string& service) | 
|  | 263 | { | 
| Ed Tanous | deae6a7 | 2024-11-11 21:58:57 -0800 | [diff] [blame] | 264 | dbus::utility::getProperty<bool>( | 
|  | 265 | service, fanPath, "xyz.openbmc_project.Inventory.Item", "Present", | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 266 | [asyncResp](const boost::system::error_code& ec, const bool value) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 267 | if (ec) | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 268 | { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 269 | if (ec.value() != EBADR) | 
|  | 270 | { | 
|  | 271 | BMCWEB_LOG_ERROR("DBUS response error for State {}", | 
|  | 272 | ec.value()); | 
|  | 273 | messages::internalError(asyncResp->res); | 
|  | 274 | } | 
|  | 275 | return; | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 276 | } | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 277 |  | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 278 | if (!value) | 
|  | 279 | { | 
|  | 280 | asyncResp->res.jsonValue["Status"]["State"] = | 
|  | 281 | resource::State::Absent; | 
|  | 282 | } | 
|  | 283 | }); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 284 | } | 
|  | 285 |  | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 286 | inline void getFanAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 287 | const std::string& fanPath, const std::string& service) | 
|  | 288 | { | 
| Ed Tanous | deae6a7 | 2024-11-11 21:58:57 -0800 | [diff] [blame] | 289 | dbus::utility::getAllProperties( | 
|  | 290 | service, fanPath, "xyz.openbmc_project.Inventory.Decorator.Asset", | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 291 | [fanPath, asyncResp{asyncResp}]( | 
|  | 292 | const boost::system::error_code& ec, | 
|  | 293 | const dbus::utility::DBusPropertiesMap& assetList) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 294 | if (ec) | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 295 | { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 296 | if (ec.value() != EBADR) | 
|  | 297 | { | 
|  | 298 | BMCWEB_LOG_ERROR("DBUS response error for Properties{}", | 
|  | 299 | ec.value()); | 
|  | 300 | messages::internalError(asyncResp->res); | 
|  | 301 | } | 
|  | 302 | return; | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 303 | } | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 304 | const std::string* manufacturer = nullptr; | 
|  | 305 | const std::string* model = nullptr; | 
|  | 306 | const std::string* partNumber = nullptr; | 
|  | 307 | const std::string* serialNumber = nullptr; | 
|  | 308 | const std::string* sparePartNumber = nullptr; | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 309 |  | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 310 | const bool success = sdbusplus::unpackPropertiesNoThrow( | 
|  | 311 | dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", | 
|  | 312 | manufacturer, "Model", model, "PartNumber", partNumber, | 
|  | 313 | "SerialNumber", serialNumber, "SparePartNumber", | 
|  | 314 | sparePartNumber); | 
|  | 315 | if (!success) | 
|  | 316 | { | 
|  | 317 | messages::internalError(asyncResp->res); | 
|  | 318 | return; | 
|  | 319 | } | 
|  | 320 | if (manufacturer != nullptr) | 
|  | 321 | { | 
|  | 322 | asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; | 
|  | 323 | } | 
|  | 324 | if (model != nullptr) | 
|  | 325 | { | 
|  | 326 | asyncResp->res.jsonValue["Model"] = *model; | 
|  | 327 | } | 
|  | 328 | if (partNumber != nullptr) | 
|  | 329 | { | 
|  | 330 | asyncResp->res.jsonValue["PartNumber"] = *partNumber; | 
|  | 331 | } | 
|  | 332 | if (serialNumber != nullptr) | 
|  | 333 | { | 
|  | 334 | asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; | 
|  | 335 | } | 
|  | 336 | if (sparePartNumber != nullptr && !sparePartNumber->empty()) | 
|  | 337 | { | 
|  | 338 | asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; | 
|  | 339 | } | 
|  | 340 | }); | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 341 | } | 
|  | 342 |  | 
| Ed Tanous | fc3edfd | 2023-07-20 12:41:30 -0700 | [diff] [blame] | 343 | inline void getFanLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 344 | const std::string& fanPath, | 
|  | 345 | const std::string& service) | 
|  | 346 | { | 
| Ed Tanous | deae6a7 | 2024-11-11 21:58:57 -0800 | [diff] [blame] | 347 | dbus::utility::getProperty<std::string>( | 
|  | 348 | service, fanPath, | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 349 | "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", | 
| Ed Tanous | fc3edfd | 2023-07-20 12:41:30 -0700 | [diff] [blame] | 350 | [asyncResp](const boost::system::error_code& ec, | 
|  | 351 | const std::string& property) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 352 | if (ec) | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 353 | { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 354 | if (ec.value() != EBADR) | 
|  | 355 | { | 
|  | 356 | BMCWEB_LOG_ERROR("DBUS response error for Location{}", | 
|  | 357 | ec.value()); | 
|  | 358 | messages::internalError(asyncResp->res); | 
|  | 359 | } | 
|  | 360 | return; | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 361 | } | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 362 | asyncResp->res | 
|  | 363 | .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = | 
|  | 364 | property; | 
|  | 365 | }); | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 366 | } | 
|  | 367 |  | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 368 | inline void | 
|  | 369 | afterGetValidFanPath(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 370 | const std::string& chassisId, const std::string& fanId, | 
|  | 371 | const std::string& fanPath, const std::string& service) | 
|  | 372 | { | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 373 | addFanCommonProperties(asyncResp->res, chassisId, fanId); | 
| Albert Zhang | 9f1ae5a | 2021-06-10 14:41:48 +0800 | [diff] [blame] | 374 | getFanState(asyncResp, fanPath, service); | 
|  | 375 | getFanHealth(asyncResp, fanPath, service); | 
| George Liu | 090ae7b | 2022-10-04 15:45:25 +0800 | [diff] [blame] | 376 | getFanAsset(asyncResp, fanPath, service); | 
| George Liu | 4a2e485 | 2022-10-04 16:13:44 +0800 | [diff] [blame] | 377 | getFanLocation(asyncResp, fanPath, service); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 378 | } | 
|  | 379 |  | 
|  | 380 | inline void doFanGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 381 | const std::string& chassisId, const std::string& fanId, | 
|  | 382 | const std::optional<std::string>& validChassisPath) | 
|  | 383 | { | 
|  | 384 | if (!validChassisPath) | 
|  | 385 | { | 
|  | 386 | messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); | 
|  | 387 | return; | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | getValidFanPath( | 
|  | 391 | asyncResp, *validChassisPath, fanId, | 
|  | 392 | std::bind_front(afterGetValidFanPath, asyncResp, chassisId, fanId)); | 
|  | 393 | } | 
|  | 394 |  | 
|  | 395 | inline void handleFanHead(App& app, const crow::Request& req, | 
|  | 396 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 397 | const std::string& chassisId, | 
|  | 398 | const std::string& fanId) | 
|  | 399 | { | 
|  | 400 | if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
|  | 401 | { | 
|  | 402 | return; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | redfish::chassis_utils::getValidChassisPath( | 
|  | 406 | asyncResp, chassisId, | 
|  | 407 | [asyncResp, chassisId, | 
|  | 408 | fanId](const std::optional<std::string>& validChassisPath) { | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 409 | if (!validChassisPath) | 
|  | 410 | { | 
|  | 411 | messages::resourceNotFound(asyncResp->res, "Chassis", | 
|  | 412 | chassisId); | 
|  | 413 | return; | 
|  | 414 | } | 
|  | 415 | getValidFanPath( | 
|  | 416 | asyncResp, *validChassisPath, fanId, | 
|  | 417 | [asyncResp](const std::string&, const std::string&) { | 
|  | 418 | asyncResp->res.addHeader( | 
|  | 419 | boost::beast::http::field::link, | 
|  | 420 | "</redfish/v1/JsonSchemas/Fan/Fan.json>; rel=describedby"); | 
|  | 421 | }); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 422 | }); | 
| George Liu | e4e5423 | 2022-09-30 09:08:11 +0800 | [diff] [blame] | 423 | } | 
|  | 424 |  | 
|  | 425 | inline void handleFanGet(App& app, const crow::Request& req, | 
|  | 426 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
|  | 427 | const std::string& chassisId, const std::string& fanId) | 
|  | 428 | { | 
|  | 429 | if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
|  | 430 | { | 
|  | 431 | return; | 
|  | 432 | } | 
|  | 433 |  | 
|  | 434 | redfish::chassis_utils::getValidChassisPath( | 
|  | 435 | asyncResp, chassisId, | 
|  | 436 | std::bind_front(doFanGet, asyncResp, chassisId, fanId)); | 
|  | 437 | } | 
|  | 438 |  | 
|  | 439 | inline void requestRoutesFan(App& app) | 
|  | 440 | { | 
|  | 441 | BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") | 
|  | 442 | .privileges(redfish::privileges::headFan) | 
|  | 443 | .methods(boost::beast::http::verb::head)( | 
|  | 444 | std::bind_front(handleFanHead, std::ref(app))); | 
|  | 445 |  | 
|  | 446 | BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/") | 
|  | 447 | .privileges(redfish::privileges::getFan) | 
|  | 448 | .methods(boost::beast::http::verb::get)( | 
|  | 449 | std::bind_front(handleFanGet, std::ref(app))); | 
|  | 450 | } | 
|  | 451 |  | 
| George Liu | 9516f41 | 2022-09-29 17:21:41 +0800 | [diff] [blame] | 452 | } // namespace redfish |