xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision a0dba87be2fb6053d52af124aabc7d6ad489ade0)
1a7210020SGeorge Liu #pragma once
2a7210020SGeorge Liu 
3a7210020SGeorge Liu #include "app.hpp"
4a7210020SGeorge Liu #include "dbus_utility.hpp"
5a7210020SGeorge Liu #include "query.hpp"
6a7210020SGeorge Liu #include "registries/privilege_registry.hpp"
7a7210020SGeorge Liu #include "utils/chassis_utils.hpp"
82b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp"
92b45fb3bSGeorge Liu #include "utils/json_utils.hpp"
10a7210020SGeorge Liu 
1134dfcb94SGeorge Liu #include <boost/system/error_code.hpp>
12ef4c65b7SEd Tanous #include <boost/url/format.hpp>
13ef4c65b7SEd Tanous 
14a7210020SGeorge Liu #include <memory>
15a7210020SGeorge Liu #include <optional>
16a7210020SGeorge Liu #include <string>
17a7210020SGeorge Liu 
18a7210020SGeorge Liu namespace redfish
19a7210020SGeorge Liu {
20a7210020SGeorge Liu 
2100ef5dc6SGeorge Liu inline void
2200ef5dc6SGeorge Liu     updatePowerSupplyList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2300ef5dc6SGeorge Liu                           const std::string& chassisId,
2400ef5dc6SGeorge Liu                           const std::string& powerSupplyPath)
25a7210020SGeorge Liu {
2600ef5dc6SGeorge Liu     std::string powerSupplyName =
2700ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
2800ef5dc6SGeorge Liu     if (powerSupplyName.empty())
2900ef5dc6SGeorge Liu     {
3000ef5dc6SGeorge Liu         return;
3100ef5dc6SGeorge Liu     }
3200ef5dc6SGeorge Liu 
3300ef5dc6SGeorge Liu     nlohmann::json item = nlohmann::json::object();
3400ef5dc6SGeorge Liu     item["@odata.id"] = boost::urls::format(
3500ef5dc6SGeorge Liu         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
3600ef5dc6SGeorge Liu         powerSupplyName);
3700ef5dc6SGeorge Liu 
3800ef5dc6SGeorge Liu     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
3900ef5dc6SGeorge Liu     powerSupplyList.emplace_back(std::move(item));
4000ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
41a7210020SGeorge Liu }
42a7210020SGeorge Liu 
43a7210020SGeorge Liu inline void
44a7210020SGeorge Liu     doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
45a7210020SGeorge Liu                             const std::string& chassisId,
46a7210020SGeorge Liu                             const std::optional<std::string>& validChassisPath)
47a7210020SGeorge Liu {
48a7210020SGeorge Liu     if (!validChassisPath)
49a7210020SGeorge Liu     {
50a7210020SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
51a7210020SGeorge Liu         return;
52a7210020SGeorge Liu     }
53a7210020SGeorge Liu 
54a7210020SGeorge Liu     asyncResp->res.addHeader(
55a7210020SGeorge Liu         boost::beast::http::field::link,
56a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
57a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
58a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
59a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
60ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
61ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
62a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
63a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
647a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
657a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
66a7210020SGeorge Liu 
67a7210020SGeorge Liu     std::string powerPath = *validChassisPath + "/powered_by";
68a7210020SGeorge Liu     dbus::utility::getAssociationEndPoints(
69a7210020SGeorge Liu         powerPath, [asyncResp, chassisId](
70a7210020SGeorge Liu                        const boost::system::error_code& ec,
71a7210020SGeorge Liu                        const dbus::utility::MapperEndPoints& endpoints) {
72a7210020SGeorge Liu             if (ec)
73a7210020SGeorge Liu             {
74a7210020SGeorge Liu                 if (ec.value() != EBADR)
75a7210020SGeorge Liu                 {
76a7210020SGeorge Liu                     BMCWEB_LOG_ERROR << "DBUS response error" << ec.value();
77a7210020SGeorge Liu                     messages::internalError(asyncResp->res);
78a7210020SGeorge Liu                 }
79a7210020SGeorge Liu                 return;
80a7210020SGeorge Liu             }
81a7210020SGeorge Liu 
82a7210020SGeorge Liu             for (const auto& endpoint : endpoints)
83a7210020SGeorge Liu             {
84a7210020SGeorge Liu                 updatePowerSupplyList(asyncResp, chassisId, endpoint);
85a7210020SGeorge Liu             }
86a7210020SGeorge Liu         });
87a7210020SGeorge Liu }
88a7210020SGeorge Liu 
89a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
90a7210020SGeorge Liu     App& app, const crow::Request& req,
91a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
92a7210020SGeorge Liu     const std::string& chassisId)
93a7210020SGeorge Liu {
94a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95a7210020SGeorge Liu     {
96a7210020SGeorge Liu         return;
97a7210020SGeorge Liu     }
98a7210020SGeorge Liu 
99a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
100a7210020SGeorge Liu         asyncResp, chassisId,
101a7210020SGeorge Liu         [asyncResp,
102a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
103a7210020SGeorge Liu         if (!validChassisPath)
104a7210020SGeorge Liu         {
105a7210020SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
106a7210020SGeorge Liu             return;
107a7210020SGeorge Liu         }
108a7210020SGeorge Liu         asyncResp->res.addHeader(
109a7210020SGeorge Liu             boost::beast::http::field::link,
110a7210020SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
111a7210020SGeorge Liu         });
112a7210020SGeorge Liu }
113a7210020SGeorge Liu 
114a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
115a7210020SGeorge Liu     App& app, const crow::Request& req,
116a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
117a7210020SGeorge Liu     const std::string& chassisId)
118a7210020SGeorge Liu {
119a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120a7210020SGeorge Liu     {
121a7210020SGeorge Liu         return;
122a7210020SGeorge Liu     }
123a7210020SGeorge Liu 
124a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
125a7210020SGeorge Liu         asyncResp, chassisId,
126a7210020SGeorge Liu         std::bind_front(doPowerSupplyCollection, asyncResp, chassisId));
127a7210020SGeorge Liu }
128a7210020SGeorge Liu 
129a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
130a7210020SGeorge Liu {
131a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
132a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
133a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
134a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
135a7210020SGeorge Liu 
136a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
137a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
138a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
139a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
140a7210020SGeorge Liu }
141a7210020SGeorge Liu 
14200ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath,
14300ef5dc6SGeorge Liu                                const std::string& powerSupplyId)
14400ef5dc6SGeorge Liu {
14500ef5dc6SGeorge Liu     std::string powerSupplyName =
14600ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
14700ef5dc6SGeorge Liu 
14800ef5dc6SGeorge Liu     return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId);
14900ef5dc6SGeorge Liu }
15000ef5dc6SGeorge Liu 
15134dfcb94SGeorge Liu inline void getValidPowerSupplyPath(
15234dfcb94SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15334dfcb94SGeorge Liu     const std::string& validChassisPath, const std::string& powerSupplyId,
15434dfcb94SGeorge Liu     std::function<void(const std::string& powerSupplyPath)>&& callback)
15500ef5dc6SGeorge Liu {
15600ef5dc6SGeorge Liu     std::string powerPath = validChassisPath + "/powered_by";
15700ef5dc6SGeorge Liu     dbus::utility::getAssociationEndPoints(
15800ef5dc6SGeorge Liu         powerPath, [asyncResp, powerSupplyId, callback{std::move(callback)}](
15900ef5dc6SGeorge Liu                        const boost::system::error_code& ec,
16000ef5dc6SGeorge Liu                        const dbus::utility::MapperEndPoints& endpoints) {
16100ef5dc6SGeorge Liu             if (ec)
16200ef5dc6SGeorge Liu             {
16300ef5dc6SGeorge Liu                 if (ec.value() != EBADR)
16400ef5dc6SGeorge Liu                 {
16500ef5dc6SGeorge Liu                     BMCWEB_LOG_ERROR
16600ef5dc6SGeorge Liu                         << "DBUS response error for getAssociationEndPoints"
16700ef5dc6SGeorge Liu                         << ec.value();
16800ef5dc6SGeorge Liu                     messages::internalError(asyncResp->res);
16900ef5dc6SGeorge Liu                     return;
17000ef5dc6SGeorge Liu                 }
17100ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
17200ef5dc6SGeorge Liu                                            powerSupplyId);
17300ef5dc6SGeorge Liu                 return;
17400ef5dc6SGeorge Liu             }
17500ef5dc6SGeorge Liu 
17600ef5dc6SGeorge Liu             for (const auto& endpoint : endpoints)
17700ef5dc6SGeorge Liu             {
17800ef5dc6SGeorge Liu                 if (checkPowerSupplyId(endpoint, powerSupplyId))
17900ef5dc6SGeorge Liu                 {
18034dfcb94SGeorge Liu                     callback(endpoint);
18100ef5dc6SGeorge Liu                     return;
18200ef5dc6SGeorge Liu                 }
18300ef5dc6SGeorge Liu             }
18400ef5dc6SGeorge Liu 
18500ef5dc6SGeorge Liu             if (!endpoints.empty())
18600ef5dc6SGeorge Liu             {
18700ef5dc6SGeorge Liu                 BMCWEB_LOG_WARNING << "Power supply not found: "
18800ef5dc6SGeorge Liu                                    << powerSupplyId;
18900ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
19000ef5dc6SGeorge Liu                                            powerSupplyId);
19100ef5dc6SGeorge Liu                 return;
19200ef5dc6SGeorge Liu             }
19300ef5dc6SGeorge Liu         });
19400ef5dc6SGeorge Liu }
19500ef5dc6SGeorge Liu 
19600ef5dc6SGeorge Liu inline void
19734dfcb94SGeorge Liu     getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19834dfcb94SGeorge Liu                         const std::string& service, const std::string& path)
19934dfcb94SGeorge Liu {
20034dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
20134dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
20234dfcb94SGeorge Liu         "xyz.openbmc_project.Inventory.Item", "Present",
20334dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
20434dfcb94SGeorge Liu         if (ec)
20534dfcb94SGeorge Liu         {
20634dfcb94SGeorge Liu             if (ec.value() != EBADR)
20734dfcb94SGeorge Liu             {
20834dfcb94SGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for State "
20934dfcb94SGeorge Liu                                  << ec.value();
21034dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
21134dfcb94SGeorge Liu             }
21234dfcb94SGeorge Liu             return;
21334dfcb94SGeorge Liu         }
21434dfcb94SGeorge Liu 
21534dfcb94SGeorge Liu         if (!value)
21634dfcb94SGeorge Liu         {
21734dfcb94SGeorge Liu             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
21834dfcb94SGeorge Liu         }
21934dfcb94SGeorge Liu         });
22034dfcb94SGeorge Liu }
22134dfcb94SGeorge Liu 
22234dfcb94SGeorge Liu inline void
22334dfcb94SGeorge Liu     getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22434dfcb94SGeorge Liu                          const std::string& service, const std::string& path)
22534dfcb94SGeorge Liu {
22634dfcb94SGeorge Liu     sdbusplus::asio::getProperty<bool>(
22734dfcb94SGeorge Liu         *crow::connections::systemBus, service, path,
22834dfcb94SGeorge Liu         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
22934dfcb94SGeorge Liu         [asyncResp](const boost::system::error_code& ec, const bool value) {
23034dfcb94SGeorge Liu         if (ec)
23134dfcb94SGeorge Liu         {
23234dfcb94SGeorge Liu             if (ec.value() != EBADR)
23334dfcb94SGeorge Liu             {
23434dfcb94SGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for Health "
23534dfcb94SGeorge Liu                                  << ec.value();
23634dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
23734dfcb94SGeorge Liu             }
23834dfcb94SGeorge Liu             return;
23934dfcb94SGeorge Liu         }
24034dfcb94SGeorge Liu 
24134dfcb94SGeorge Liu         if (!value)
24234dfcb94SGeorge Liu         {
24334dfcb94SGeorge Liu             asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
24434dfcb94SGeorge Liu         }
24534dfcb94SGeorge Liu         });
24634dfcb94SGeorge Liu }
24734dfcb94SGeorge Liu 
24834dfcb94SGeorge Liu inline void
2492b45fb3bSGeorge Liu     getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2502b45fb3bSGeorge Liu                         const std::string& service, const std::string& path)
2512b45fb3bSGeorge Liu {
2522b45fb3bSGeorge Liu     sdbusplus::asio::getAllProperties(
2532b45fb3bSGeorge Liu         *crow::connections::systemBus, service, path,
2542b45fb3bSGeorge Liu         "xyz.openbmc_project.Inventory.Decorator.Asset",
2552b45fb3bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
2562b45fb3bSGeorge Liu                     const dbus::utility::DBusPropertiesMap& propertiesList) {
2572b45fb3bSGeorge Liu         if (ec)
2582b45fb3bSGeorge Liu         {
2592b45fb3bSGeorge Liu             if (ec.value() != EBADR)
2602b45fb3bSGeorge Liu             {
2612b45fb3bSGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for Asset "
2622b45fb3bSGeorge Liu                                  << ec.value();
2632b45fb3bSGeorge Liu                 messages::internalError(asyncResp->res);
2642b45fb3bSGeorge Liu             }
2652b45fb3bSGeorge Liu             return;
2662b45fb3bSGeorge Liu         }
2672b45fb3bSGeorge Liu 
2682b45fb3bSGeorge Liu         const std::string* partNumber = nullptr;
2692b45fb3bSGeorge Liu         const std::string* serialNumber = nullptr;
2702b45fb3bSGeorge Liu         const std::string* manufacturer = nullptr;
2712b45fb3bSGeorge Liu         const std::string* model = nullptr;
2722b45fb3bSGeorge Liu         const std::string* sparePartNumber = nullptr;
2732b45fb3bSGeorge Liu 
2742b45fb3bSGeorge Liu         const bool success = sdbusplus::unpackPropertiesNoThrow(
2752b45fb3bSGeorge Liu             dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
2762b45fb3bSGeorge Liu             partNumber, "SerialNumber", serialNumber, "Manufacturer",
2772b45fb3bSGeorge Liu             manufacturer, "Model", model, "SparePartNumber", sparePartNumber);
2782b45fb3bSGeorge Liu 
2792b45fb3bSGeorge Liu         if (!success)
2802b45fb3bSGeorge Liu         {
2812b45fb3bSGeorge Liu             messages::internalError(asyncResp->res);
2822b45fb3bSGeorge Liu             return;
2832b45fb3bSGeorge Liu         }
2842b45fb3bSGeorge Liu 
2852b45fb3bSGeorge Liu         if (partNumber != nullptr)
2862b45fb3bSGeorge Liu         {
2872b45fb3bSGeorge Liu             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
2882b45fb3bSGeorge Liu         }
2892b45fb3bSGeorge Liu 
2902b45fb3bSGeorge Liu         if (serialNumber != nullptr)
2912b45fb3bSGeorge Liu         {
2922b45fb3bSGeorge Liu             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
2932b45fb3bSGeorge Liu         }
2942b45fb3bSGeorge Liu 
2952b45fb3bSGeorge Liu         if (manufacturer != nullptr)
2962b45fb3bSGeorge Liu         {
2972b45fb3bSGeorge Liu             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
2982b45fb3bSGeorge Liu         }
2992b45fb3bSGeorge Liu 
3002b45fb3bSGeorge Liu         if (model != nullptr)
3012b45fb3bSGeorge Liu         {
3022b45fb3bSGeorge Liu             asyncResp->res.jsonValue["Model"] = *model;
3032b45fb3bSGeorge Liu         }
3042b45fb3bSGeorge Liu 
3052b45fb3bSGeorge Liu         // SparePartNumber is optional on D-Bus so skip if it is empty
3062b45fb3bSGeorge Liu         if (sparePartNumber != nullptr && !sparePartNumber->empty())
3072b45fb3bSGeorge Liu         {
3082b45fb3bSGeorge Liu             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
3092b45fb3bSGeorge Liu         }
3102b45fb3bSGeorge Liu         });
3112b45fb3bSGeorge Liu }
3122b45fb3bSGeorge Liu 
313*a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion(
314*a0dba87bSGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
315*a0dba87bSGeorge Liu     const std::string& service, const std::string& path)
316*a0dba87bSGeorge Liu {
317*a0dba87bSGeorge Liu     sdbusplus::asio::getProperty<std::string>(
318*a0dba87bSGeorge Liu         *crow::connections::systemBus, service, path,
319*a0dba87bSGeorge Liu         "xyz.openbmc_project.Software.Version", "Version",
320*a0dba87bSGeorge Liu         [asyncResp](const boost::system::error_code& ec,
321*a0dba87bSGeorge Liu                     const std::string& value) {
322*a0dba87bSGeorge Liu         if (ec)
323*a0dba87bSGeorge Liu         {
324*a0dba87bSGeorge Liu             if (ec.value() != EBADR)
325*a0dba87bSGeorge Liu             {
326*a0dba87bSGeorge Liu                 BMCWEB_LOG_ERROR << "DBUS response error for FirmwareVersion "
327*a0dba87bSGeorge Liu                                  << ec.value();
328*a0dba87bSGeorge Liu                 messages::internalError(asyncResp->res);
329*a0dba87bSGeorge Liu             }
330*a0dba87bSGeorge Liu             return;
331*a0dba87bSGeorge Liu         }
332*a0dba87bSGeorge Liu         asyncResp->res.jsonValue["FirmwareVersion"] = value;
333*a0dba87bSGeorge Liu         });
334*a0dba87bSGeorge Liu }
335*a0dba87bSGeorge Liu 
3362b45fb3bSGeorge Liu inline void
33700ef5dc6SGeorge Liu     doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
33800ef5dc6SGeorge Liu                      const std::string& chassisId,
33900ef5dc6SGeorge Liu                      const std::string& powerSupplyId,
34000ef5dc6SGeorge Liu                      const std::optional<std::string>& validChassisPath)
34100ef5dc6SGeorge Liu {
34200ef5dc6SGeorge Liu     if (!validChassisPath)
34300ef5dc6SGeorge Liu     {
34400ef5dc6SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
34500ef5dc6SGeorge Liu         return;
34600ef5dc6SGeorge Liu     }
34700ef5dc6SGeorge Liu 
34800ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
34900ef5dc6SGeorge Liu     getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
35034dfcb94SGeorge Liu                             [asyncResp, chassisId, powerSupplyId](
35134dfcb94SGeorge Liu                                 const std::string& powerSupplyPath) {
35200ef5dc6SGeorge Liu         asyncResp->res.addHeader(
35300ef5dc6SGeorge Liu             boost::beast::http::field::link,
35400ef5dc6SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
35500ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.type"] =
35600ef5dc6SGeorge Liu             "#PowerSupply.v1_5_0.PowerSupply";
35700ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Name"] = "Power Supply";
35800ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Id"] = powerSupplyId;
35900ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
36000ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
36100ef5dc6SGeorge Liu             powerSupplyId);
36234dfcb94SGeorge Liu 
36334dfcb94SGeorge Liu         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
36434dfcb94SGeorge Liu         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
36534dfcb94SGeorge Liu 
36634dfcb94SGeorge Liu         constexpr std::array<std::string_view, 1> interfaces = {
36734dfcb94SGeorge Liu             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
36834dfcb94SGeorge Liu         dbus::utility::getDbusObject(
36934dfcb94SGeorge Liu             powerSupplyPath, interfaces,
37034dfcb94SGeorge Liu             [asyncResp,
37134dfcb94SGeorge Liu              powerSupplyPath](const boost::system::error_code& ec,
37234dfcb94SGeorge Liu                               const dbus::utility::MapperGetObject& object) {
37334dfcb94SGeorge Liu             if (ec || object.empty())
37434dfcb94SGeorge Liu             {
37534dfcb94SGeorge Liu                 messages::internalError(asyncResp->res);
37634dfcb94SGeorge Liu                 return;
37734dfcb94SGeorge Liu             }
37834dfcb94SGeorge Liu 
37934dfcb94SGeorge Liu             getPowerSupplyState(asyncResp, object.begin()->first,
38034dfcb94SGeorge Liu                                 powerSupplyPath);
38134dfcb94SGeorge Liu             getPowerSupplyHealth(asyncResp, object.begin()->first,
38234dfcb94SGeorge Liu                                  powerSupplyPath);
3832b45fb3bSGeorge Liu             getPowerSupplyAsset(asyncResp, object.begin()->first,
3842b45fb3bSGeorge Liu                                 powerSupplyPath);
385*a0dba87bSGeorge Liu             getPowerSupplyFirmwareVersion(asyncResp, object.begin()->first,
386*a0dba87bSGeorge Liu                                           powerSupplyPath);
38734dfcb94SGeorge Liu             });
38800ef5dc6SGeorge Liu     });
38900ef5dc6SGeorge Liu }
39000ef5dc6SGeorge Liu 
39100ef5dc6SGeorge Liu inline void
39200ef5dc6SGeorge Liu     handlePowerSupplyHead(App& app, const crow::Request& req,
39300ef5dc6SGeorge Liu                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
39400ef5dc6SGeorge Liu                           const std::string& chassisId,
39500ef5dc6SGeorge Liu                           const std::string& powerSupplyId)
39600ef5dc6SGeorge Liu {
39700ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
39800ef5dc6SGeorge Liu     {
39900ef5dc6SGeorge Liu         return;
40000ef5dc6SGeorge Liu     }
40100ef5dc6SGeorge Liu 
40200ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
40300ef5dc6SGeorge Liu         asyncResp, chassisId,
40400ef5dc6SGeorge Liu         [asyncResp, chassisId,
40500ef5dc6SGeorge Liu          powerSupplyId](const std::optional<std::string>& validChassisPath) {
40600ef5dc6SGeorge Liu         if (!validChassisPath)
40700ef5dc6SGeorge Liu         {
40800ef5dc6SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
40900ef5dc6SGeorge Liu             return;
41000ef5dc6SGeorge Liu         }
41100ef5dc6SGeorge Liu 
41200ef5dc6SGeorge Liu         // Get the correct Path and Service that match the input parameters
41300ef5dc6SGeorge Liu         getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
41434dfcb94SGeorge Liu                                 [asyncResp](const std::string&) {
41500ef5dc6SGeorge Liu             asyncResp->res.addHeader(
41600ef5dc6SGeorge Liu                 boost::beast::http::field::link,
41700ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
41800ef5dc6SGeorge Liu         });
41900ef5dc6SGeorge Liu         });
42000ef5dc6SGeorge Liu }
42100ef5dc6SGeorge Liu 
42200ef5dc6SGeorge Liu inline void
42300ef5dc6SGeorge Liu     handlePowerSupplyGet(App& app, const crow::Request& req,
42400ef5dc6SGeorge Liu                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
42500ef5dc6SGeorge Liu                          const std::string& chassisId,
42600ef5dc6SGeorge Liu                          const std::string& powerSupplyId)
42700ef5dc6SGeorge Liu {
42800ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
42900ef5dc6SGeorge Liu     {
43000ef5dc6SGeorge Liu         return;
43100ef5dc6SGeorge Liu     }
43200ef5dc6SGeorge Liu 
43300ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
43400ef5dc6SGeorge Liu         asyncResp, chassisId,
43500ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
43600ef5dc6SGeorge Liu }
43700ef5dc6SGeorge Liu 
43800ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
43900ef5dc6SGeorge Liu {
44000ef5dc6SGeorge Liu     BMCWEB_ROUTE(
44100ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
44200ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
44300ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
44400ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
44500ef5dc6SGeorge Liu 
44600ef5dc6SGeorge Liu     BMCWEB_ROUTE(
44700ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
44800ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
44900ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
45000ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
45100ef5dc6SGeorge Liu }
45200ef5dc6SGeorge Liu 
453a7210020SGeorge Liu } // namespace redfish
454