blob: 7316b5f63f218cc2830637e40cc36723895c0f58 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
George Liua7210022022-10-05 15:44:11 +08003#pragma once
4
5#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08006#include "async_resp.hpp"
George Liua7210022022-10-05 15:44:11 +08007#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08008#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -07009#include "generated/enums/resource.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080010#include "http_request.hpp"
11#include "logging.hpp"
George Liua7210022022-10-05 15:44:11 +080012#include "query.hpp"
13#include "registries/privilege_registry.hpp"
14#include "utils/chassis_utils.hpp"
George Liu2b45fb32022-10-05 17:00:00 +080015#include "utils/dbus_utils.hpp"
Hieu Huynhb5190062024-07-11 03:47:21 +000016#include "utils/time_utils.hpp"
George Liua7210022022-10-05 15:44:11 +080017
Ed Tanousd7857202025-01-28 15:32:26 -080018#include <asm-generic/errno.h>
19
20#include <boost/beast/http/field.hpp>
21#include <boost/beast/http/verb.hpp>
George Liu34dfcb92022-10-05 16:47:44 +080022#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070023#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080024#include <nlohmann/json.hpp>
25#include <sdbusplus/unpack_properties.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070026
Ed Tanousd7857202025-01-28 15:32:26 -080027#include <array>
28#include <cstdint>
29#include <functional>
George Liua7210022022-10-05 15:44:11 +080030#include <memory>
31#include <optional>
32#include <string>
Ed Tanousd7857202025-01-28 15:32:26 -080033#include <string_view>
34#include <utility>
George Liua7210022022-10-05 15:44:11 +080035
36namespace redfish
37{
38
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -050039static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
40 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
41
42inline void updatePowerSupplyList(
43 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
44 const std::string& chassisId,
45 const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
George Liua7210022022-10-05 15:44:11 +080046{
George Liu00ef5dc2022-10-05 16:27:52 +080047 nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -050048 for (const std::string& powerSupplyPath : powerSupplyPaths)
49 {
50 std::string powerSupplyName =
51 sdbusplus::message::object_path(powerSupplyPath).filename();
52 if (powerSupplyName.empty())
53 {
54 continue;
55 }
56
57 nlohmann::json item = nlohmann::json::object();
58 item["@odata.id"] = boost::urls::format(
59 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
60 powerSupplyName);
61
62 powerSupplyList.emplace_back(std::move(item));
63 }
George Liu00ef5dc2022-10-05 16:27:52 +080064 asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
George Liua7210022022-10-05 15:44:11 +080065}
66
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050067inline void doPowerSupplyCollection(
68 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
69 const std::string& chassisId, const boost::system::error_code& ec,
70 const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
George Liua7210022022-10-05 15:44:11 +080071{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050072 if (ec)
George Liua7210022022-10-05 15:44:11 +080073 {
Myung Bae193582b2025-03-31 07:21:31 -050074 if (ec.value() == boost::system::errc::io_error)
75 {
76 BMCWEB_LOG_WARNING("Chassis not found");
77 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
78 return;
79 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -050080 if (ec.value() != EBADR)
81 {
82 BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
83 messages::internalError(asyncResp->res);
84 }
George Liua7210022022-10-05 15:44:11 +080085 return;
86 }
George Liua7210022022-10-05 15:44:11 +080087 asyncResp->res.addHeader(
88 boost::beast::http::field::link,
89 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
90 asyncResp->res.jsonValue["@odata.type"] =
91 "#PowerSupplyCollection.PowerSupplyCollection";
92 asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
Ed Tanousef4c65b2023-04-24 15:28:50 -070093 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
94 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
George Liua7210022022-10-05 15:44:11 +080095 asyncResp->res.jsonValue["Description"] =
96 "The collection of PowerSupply resource instances.";
George Liu7a2bb2c2023-04-11 10:44:33 +080097 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
98 asyncResp->res.jsonValue["Members@odata.count"] = 0;
George Liua7210022022-10-05 15:44:11 +080099
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500100 updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
George Liua7210022022-10-05 15:44:11 +0800101}
102
103inline void handlePowerSupplyCollectionHead(
104 App& app, const crow::Request& req,
105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
106 const std::string& chassisId)
107{
108 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
109 {
110 return;
111 }
112
113 redfish::chassis_utils::getValidChassisPath(
114 asyncResp, chassisId,
115 [asyncResp,
116 chassisId](const std::optional<std::string>& validChassisPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400117 if (!validChassisPath)
118 {
Myung Bae193582b2025-03-31 07:21:31 -0500119 BMCWEB_LOG_WARNING("Chassis not found");
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400120 messages::resourceNotFound(asyncResp->res, "Chassis",
121 chassisId);
122 return;
123 }
124 asyncResp->res.addHeader(
125 boost::beast::http::field::link,
126 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
127 });
George Liua7210022022-10-05 15:44:11 +0800128}
129
130inline void handlePowerSupplyCollectionGet(
131 App& app, const crow::Request& req,
132 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
133 const std::string& chassisId)
134{
135 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
136 {
137 return;
138 }
139
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500140 const std::string reqpath = "/xyz/openbmc_project/inventory";
141
142 dbus::utility::getAssociatedSubTreePathsById(
Myung Bae3f95a272024-03-13 07:32:02 -0700143 chassisId, reqpath, chassisInterfaces, "powered_by",
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500144 powerSupplyInterface,
145 [asyncResp, chassisId](
146 const boost::system::error_code& ec,
147 const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
148 doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
149 });
George Liua7210022022-10-05 15:44:11 +0800150}
151
152inline void requestRoutesPowerSupplyCollection(App& app)
153{
154 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
155 .privileges(redfish::privileges::headPowerSupplyCollection)
156 .methods(boost::beast::http::verb::head)(
157 std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
158
159 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
160 .privileges(redfish::privileges::getPowerSupplyCollection)
161 .methods(boost::beast::http::verb::get)(
162 std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
163}
164
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500165inline void afterGetValidPowerSupplyPath(
166 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
167 const std::string& powerSupplyId, const boost::system::error_code& ec,
168 const dbus::utility::MapperGetSubTreeResponse& subtree,
169 const std::function<void(const std::string& powerSupplyPath,
170 const std::string& service)>& callback)
George Liu00ef5dc2022-10-05 16:27:52 +0800171{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500172 if (ec)
173 {
Myung Bae193582b2025-03-31 07:21:31 -0500174 if (ec.value() == boost::system::errc::io_error)
175 {
176 // Not found
177 callback(std::string(), std::string());
178 return;
179 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500180 if (ec.value() != EBADR)
181 {
182 BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
183 messages::internalError(asyncResp->res);
Myung Bae193582b2025-03-31 07:21:31 -0500184 return;
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500185 }
Myung Bae193582b2025-03-31 07:21:31 -0500186 callback(std::string(), std::string());
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500187 return;
188 }
189 for (const auto& [objectPath, service] : subtree)
190 {
191 sdbusplus::message::object_path path(objectPath);
Myung Baed8e2b612024-10-08 12:19:19 -0500192 if (path.filename() == powerSupplyId)
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500193 {
194 callback(path, service.begin()->first);
195 return;
196 }
197 }
George Liu00ef5dc2022-10-05 16:27:52 +0800198
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500199 BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
200 messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
George Liu00ef5dc2022-10-05 16:27:52 +0800201}
202
George Liu34dfcb92022-10-05 16:47:44 +0800203inline void getValidPowerSupplyPath(
204 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500205 const std::string& chassisId, const std::string& powerSupplyId,
206 std::function<void(const std::string& powerSupplyPath,
207 const std::string& service)>&& callback)
George Liu00ef5dc2022-10-05 16:27:52 +0800208{
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500209 const std::string reqpath = "/xyz/openbmc_project/inventory";
210
211 dbus::utility::getAssociatedSubTreeById(
Myung Bae3f95a272024-03-13 07:32:02 -0700212 chassisId, reqpath, chassisInterfaces, "powered_by",
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -0500213 powerSupplyInterface,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500214 [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
Lakshmi Yadlapati788fe6c2023-06-21 14:39:08 -0500215 const boost::system::error_code& ec,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500216 const dbus::utility::MapperGetSubTreeResponse& subtree) {
217 afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
218 callback);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400219 });
George Liu00ef5dc2022-10-05 16:27:52 +0800220}
221
Patrick Williams504af5a2025-02-03 14:29:03 -0500222inline void getPowerSupplyState(
223 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
224 const std::string& service, const std::string& path)
George Liu34dfcb92022-10-05 16:47:44 +0800225{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800226 dbus::utility::getProperty<bool>(
227 service, path, "xyz.openbmc_project.Inventory.Item", "Present",
George Liu34dfcb92022-10-05 16:47:44 +0800228 [asyncResp](const boost::system::error_code& ec, const bool value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400229 if (ec)
George Liu34dfcb92022-10-05 16:47:44 +0800230 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400231 if (ec.value() != EBADR)
232 {
233 BMCWEB_LOG_ERROR("DBUS response error for State {}",
234 ec.value());
235 messages::internalError(asyncResp->res);
236 }
237 return;
George Liu34dfcb92022-10-05 16:47:44 +0800238 }
George Liu34dfcb92022-10-05 16:47:44 +0800239
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400240 if (!value)
241 {
242 asyncResp->res.jsonValue["Status"]["State"] =
243 resource::State::Absent;
244 }
245 });
George Liu34dfcb92022-10-05 16:47:44 +0800246}
247
Patrick Williams504af5a2025-02-03 14:29:03 -0500248inline void getPowerSupplyHealth(
249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
250 const std::string& service, const std::string& path)
George Liu34dfcb92022-10-05 16:47:44 +0800251{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800252 dbus::utility::getProperty<bool>(
253 service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
254 "Functional",
George Liu34dfcb92022-10-05 16:47:44 +0800255 [asyncResp](const boost::system::error_code& ec, const bool value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400256 if (ec)
George Liu34dfcb92022-10-05 16:47:44 +0800257 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400258 if (ec.value() != EBADR)
259 {
260 BMCWEB_LOG_ERROR("DBUS response error for Health {}",
261 ec.value());
262 messages::internalError(asyncResp->res);
263 }
264 return;
George Liu34dfcb92022-10-05 16:47:44 +0800265 }
George Liu34dfcb92022-10-05 16:47:44 +0800266
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400267 if (!value)
268 {
269 asyncResp->res.jsonValue["Status"]["Health"] =
270 resource::Health::Critical;
271 }
272 });
George Liu34dfcb92022-10-05 16:47:44 +0800273}
274
Patrick Williams504af5a2025-02-03 14:29:03 -0500275inline void getPowerSupplyAsset(
276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
277 const std::string& service, const std::string& path)
George Liu2b45fb32022-10-05 17:00:00 +0800278{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800279 dbus::utility::getAllProperties(
280 service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
George Liu2b45fb32022-10-05 17:00:00 +0800281 [asyncResp](const boost::system::error_code& ec,
282 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400283 if (ec)
George Liu2b45fb32022-10-05 17:00:00 +0800284 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400285 if (ec.value() != EBADR)
286 {
287 BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
288 ec.value());
289 messages::internalError(asyncResp->res);
290 }
291 return;
George Liu2b45fb32022-10-05 17:00:00 +0800292 }
George Liu2b45fb32022-10-05 17:00:00 +0800293
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400294 const std::string* partNumber = nullptr;
295 const std::string* serialNumber = nullptr;
296 const std::string* manufacturer = nullptr;
297 const std::string* model = nullptr;
298 const std::string* sparePartNumber = nullptr;
Hieu Huynhb5190062024-07-11 03:47:21 +0000299 const std::string* buildDate = nullptr;
George Liu2b45fb32022-10-05 17:00:00 +0800300
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400301 const bool success = sdbusplus::unpackPropertiesNoThrow(
302 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
303 partNumber, "SerialNumber", serialNumber, "Manufacturer",
304 manufacturer, "Model", model, "SparePartNumber",
Hieu Huynhb5190062024-07-11 03:47:21 +0000305 sparePartNumber, "BuildDate", buildDate);
George Liu2b45fb32022-10-05 17:00:00 +0800306
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400307 if (!success)
308 {
309 messages::internalError(asyncResp->res);
310 return;
311 }
George Liu2b45fb32022-10-05 17:00:00 +0800312
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400313 if (partNumber != nullptr)
314 {
315 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
316 }
George Liu2b45fb32022-10-05 17:00:00 +0800317
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400318 if (serialNumber != nullptr)
319 {
320 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
321 }
George Liu2b45fb32022-10-05 17:00:00 +0800322
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400323 if (manufacturer != nullptr)
324 {
325 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
326 }
George Liu2b45fb32022-10-05 17:00:00 +0800327
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400328 if (model != nullptr)
329 {
330 asyncResp->res.jsonValue["Model"] = *model;
331 }
George Liu2b45fb32022-10-05 17:00:00 +0800332
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400333 // SparePartNumber is optional on D-Bus so skip if it is empty
334 if (sparePartNumber != nullptr && !sparePartNumber->empty())
335 {
336 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
337 }
Hieu Huynhb5190062024-07-11 03:47:21 +0000338
339 if (buildDate != nullptr)
340 {
341 time_utils::productionDateReport(asyncResp->res, *buildDate);
342 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400343 });
George Liu2b45fb32022-10-05 17:00:00 +0800344}
345
George Liua0dba872022-10-05 17:03:20 +0800346inline void getPowerSupplyFirmwareVersion(
347 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
348 const std::string& service, const std::string& path)
349{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800350 dbus::utility::getProperty<std::string>(
351 service, path, "xyz.openbmc_project.Software.Version", "Version",
George Liua0dba872022-10-05 17:03:20 +0800352 [asyncResp](const boost::system::error_code& ec,
353 const std::string& value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400354 if (ec)
George Liua0dba872022-10-05 17:03:20 +0800355 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400356 if (ec.value() != EBADR)
357 {
358 BMCWEB_LOG_ERROR(
359 "DBUS response error for FirmwareVersion {}",
360 ec.value());
361 messages::internalError(asyncResp->res);
362 }
363 return;
George Liua0dba872022-10-05 17:03:20 +0800364 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400365 asyncResp->res.jsonValue["FirmwareVersion"] = value;
366 });
George Liua0dba872022-10-05 17:03:20 +0800367}
368
Patrick Williams504af5a2025-02-03 14:29:03 -0500369inline void getPowerSupplyLocation(
370 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
371 const std::string& service, const std::string& path)
George Liu44845e52022-10-05 17:09:21 +0800372{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800373 dbus::utility::getProperty<std::string>(
374 service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
375 "LocationCode",
George Liu44845e52022-10-05 17:09:21 +0800376 [asyncResp](const boost::system::error_code& ec,
377 const std::string& value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400378 if (ec)
George Liu44845e52022-10-05 17:09:21 +0800379 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400380 if (ec.value() != EBADR)
381 {
382 BMCWEB_LOG_ERROR("DBUS response error for Location {}",
383 ec.value());
384 messages::internalError(asyncResp->res);
385 }
386 return;
George Liu44845e52022-10-05 17:09:21 +0800387 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400388 asyncResp->res
389 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
390 });
George Liu44845e52022-10-05 17:09:21 +0800391}
392
George Liuddceee02022-10-06 08:57:11 +0800393inline void handleGetEfficiencyResponse(
394 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
395 const boost::system::error_code& ec, uint32_t value)
396{
397 if (ec)
398 {
399 if (ec.value() != EBADR)
400 {
Ed Tanous62598e32023-07-17 17:06:25 -0700401 BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
402 ec.value());
George Liuddceee02022-10-06 08:57:11 +0800403 messages::internalError(asyncResp->res);
404 }
405 return;
406 }
407 // The PDI default value is 0, if it hasn't been set leave off
408 if (value == 0)
409 {
410 return;
411 }
412
413 nlohmann::json::array_t efficiencyRatings;
414 nlohmann::json::object_t efficiencyPercent;
415 efficiencyPercent["EfficiencyPercent"] = value;
416 efficiencyRatings.emplace_back(std::move(efficiencyPercent));
417 asyncResp->res.jsonValue["EfficiencyRatings"] =
418 std::move(efficiencyRatings);
419}
420
421inline void handlePowerSupplyAttributesSubTreeResponse(
422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
423 const boost::system::error_code& ec,
424 const dbus::utility::MapperGetSubTreeResponse& subtree)
425{
426 if (ec)
427 {
428 if (ec.value() != EBADR)
429 {
Ed Tanous62598e32023-07-17 17:06:25 -0700430 BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
431 ec.value());
George Liuddceee02022-10-06 08:57:11 +0800432 messages::internalError(asyncResp->res);
433 }
434 return;
435 }
436
437 if (subtree.empty())
438 {
Ed Tanous62598e32023-07-17 17:06:25 -0700439 BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
George Liuddceee02022-10-06 08:57:11 +0800440 return;
441 }
442
443 if (subtree.size() != 1)
444 {
Ed Tanous62598e32023-07-17 17:06:25 -0700445 BMCWEB_LOG_ERROR(
446 "Unexpected number of paths returned by getSubTree: {}",
447 subtree.size());
George Liuddceee02022-10-06 08:57:11 +0800448 messages::internalError(asyncResp->res);
449 return;
450 }
451
452 const auto& [path, serviceMap] = *subtree.begin();
453 const auto& [service, interfaces] = *serviceMap.begin();
Ed Tanousdeae6a72024-11-11 21:58:57 -0800454 dbus::utility::getProperty<uint32_t>(
455 service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
456 "DeratingFactor",
George Liuddceee02022-10-06 08:57:11 +0800457 [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400458 handleGetEfficiencyResponse(asyncResp, ec1, value);
459 });
George Liuddceee02022-10-06 08:57:11 +0800460}
461
Patrick Williams504af5a2025-02-03 14:29:03 -0500462inline void getEfficiencyPercent(
463 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
George Liuddceee02022-10-06 08:57:11 +0800464{
465 constexpr std::array<std::string_view, 1> efficiencyIntf = {
466 "xyz.openbmc_project.Control.PowerSupplyAttributes"};
467
468 dbus::utility::getSubTree(
469 "/xyz/openbmc_project", 0, efficiencyIntf,
470 [asyncResp](const boost::system::error_code& ec,
471 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400472 handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
473 });
George Liuddceee02022-10-06 08:57:11 +0800474}
475
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400476inline void doPowerSupplyGet(
477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
478 const std::string& chassisId, const std::string& powerSupplyId,
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500479 const std::string& powerSupplyPath, const std::string& service)
George Liu00ef5dc2022-10-05 16:27:52 +0800480{
Myung Bae193582b2025-03-31 07:21:31 -0500481 if (powerSupplyPath.empty() || service.empty())
482 {
483 BMCWEB_LOG_WARNING("PowerSupply not found");
484 messages::resourceNotFound(asyncResp->res, "PowerSupply",
485 powerSupplyId);
486 return;
487 }
488
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500489 asyncResp->res.addHeader(
490 boost::beast::http::field::link,
491 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
492 asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
493 asyncResp->res.jsonValue["Name"] = "Power Supply";
494 asyncResp->res.jsonValue["Id"] = powerSupplyId;
495 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
496 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
497 powerSupplyId);
George Liu00ef5dc2022-10-05 16:27:52 +0800498
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500499 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
500 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
George Liu34dfcb92022-10-05 16:47:44 +0800501
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500502 getPowerSupplyState(asyncResp, service, powerSupplyPath);
503 getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
504 getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
505 getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
506 getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
507 getEfficiencyPercent(asyncResp);
George Liu00ef5dc2022-10-05 16:27:52 +0800508}
509
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400510inline void handlePowerSupplyHead(
511 App& app, const crow::Request& req,
512 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
513 const std::string& chassisId, const std::string& powerSupplyId)
George Liu00ef5dc2022-10-05 16:27:52 +0800514{
515 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
516 {
517 return;
518 }
519
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500520 // Get the correct Path and Service that match the input parameters
521 getValidPowerSupplyPath(
522 asyncResp, chassisId, powerSupplyId,
Myung Bae193582b2025-03-31 07:21:31 -0500523 [asyncResp, powerSupplyId](const std::string& powerSupplyPath,
524 const std::string& service) {
525 if (powerSupplyPath.empty() || service.empty())
526 {
527 BMCWEB_LOG_WARNING("PowerSupply not found");
528 messages::resourceNotFound(asyncResp->res, "PowerSupply",
529 powerSupplyId);
530 return;
531 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500532 asyncResp->res.addHeader(
533 boost::beast::http::field::link,
534 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
George Liu00ef5dc2022-10-05 16:27:52 +0800535 });
George Liu00ef5dc2022-10-05 16:27:52 +0800536}
537
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400538inline void handlePowerSupplyGet(
539 App& app, const crow::Request& req,
540 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
541 const std::string& chassisId, const std::string& powerSupplyId)
George Liu00ef5dc2022-10-05 16:27:52 +0800542{
543 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
544 {
545 return;
546 }
Lakshmi Yadlapati3e42a322024-06-26 18:28:06 -0500547 getValidPowerSupplyPath(
548 asyncResp, chassisId, powerSupplyId,
George Liu00ef5dc2022-10-05 16:27:52 +0800549 std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
550}
551
552inline void requestRoutesPowerSupply(App& app)
553{
554 BMCWEB_ROUTE(
555 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
556 .privileges(redfish::privileges::headPowerSupply)
557 .methods(boost::beast::http::verb::head)(
558 std::bind_front(handlePowerSupplyHead, std::ref(app)));
559
560 BMCWEB_ROUTE(
561 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
562 .privileges(redfish::privileges::getPowerSupply)
563 .methods(boost::beast::http::verb::get)(
564 std::bind_front(handlePowerSupplyGet, std::ref(app)));
565}
566
George Liua7210022022-10-05 15:44:11 +0800567} // namespace redfish