xref: /openbmc/bmcweb/features/redfish/lib/power_supply.hpp (revision 00ef5dc6d410ab83302529f23919b3d91a35b5e3)
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"
8a7210020SGeorge Liu 
9ef4c65b7SEd Tanous #include <boost/url/format.hpp>
10ef4c65b7SEd Tanous 
11a7210020SGeorge Liu #include <memory>
12a7210020SGeorge Liu #include <optional>
13a7210020SGeorge Liu #include <string>
14a7210020SGeorge Liu 
15a7210020SGeorge Liu namespace redfish
16a7210020SGeorge Liu {
17a7210020SGeorge Liu 
18*00ef5dc6SGeorge Liu inline void
19*00ef5dc6SGeorge Liu     updatePowerSupplyList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20*00ef5dc6SGeorge Liu                           const std::string& chassisId,
21*00ef5dc6SGeorge Liu                           const std::string& powerSupplyPath)
22a7210020SGeorge Liu {
23*00ef5dc6SGeorge Liu     std::string powerSupplyName =
24*00ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
25*00ef5dc6SGeorge Liu     if (powerSupplyName.empty())
26*00ef5dc6SGeorge Liu     {
27*00ef5dc6SGeorge Liu         return;
28*00ef5dc6SGeorge Liu     }
29*00ef5dc6SGeorge Liu 
30*00ef5dc6SGeorge Liu     nlohmann::json item = nlohmann::json::object();
31*00ef5dc6SGeorge Liu     item["@odata.id"] = boost::urls::format(
32*00ef5dc6SGeorge Liu         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
33*00ef5dc6SGeorge Liu         powerSupplyName);
34*00ef5dc6SGeorge Liu 
35*00ef5dc6SGeorge Liu     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
36*00ef5dc6SGeorge Liu     powerSupplyList.emplace_back(std::move(item));
37*00ef5dc6SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
38a7210020SGeorge Liu }
39a7210020SGeorge Liu 
40a7210020SGeorge Liu inline void
41a7210020SGeorge Liu     doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
42a7210020SGeorge Liu                             const std::string& chassisId,
43a7210020SGeorge Liu                             const std::optional<std::string>& validChassisPath)
44a7210020SGeorge Liu {
45a7210020SGeorge Liu     if (!validChassisPath)
46a7210020SGeorge Liu     {
47a7210020SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
48a7210020SGeorge Liu         return;
49a7210020SGeorge Liu     }
50a7210020SGeorge Liu 
51a7210020SGeorge Liu     asyncResp->res.addHeader(
52a7210020SGeorge Liu         boost::beast::http::field::link,
53a7210020SGeorge Liu         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
54a7210020SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] =
55a7210020SGeorge Liu         "#PowerSupplyCollection.PowerSupplyCollection";
56a7210020SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
57ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
58ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
59a7210020SGeorge Liu     asyncResp->res.jsonValue["Description"] =
60a7210020SGeorge Liu         "The collection of PowerSupply resource instances.";
617a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
627a2bb2c9SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = 0;
63a7210020SGeorge Liu 
64a7210020SGeorge Liu     std::string powerPath = *validChassisPath + "/powered_by";
65a7210020SGeorge Liu     dbus::utility::getAssociationEndPoints(
66a7210020SGeorge Liu         powerPath, [asyncResp, chassisId](
67a7210020SGeorge Liu                        const boost::system::error_code& ec,
68a7210020SGeorge Liu                        const dbus::utility::MapperEndPoints& endpoints) {
69a7210020SGeorge Liu             if (ec)
70a7210020SGeorge Liu             {
71a7210020SGeorge Liu                 if (ec.value() != EBADR)
72a7210020SGeorge Liu                 {
73a7210020SGeorge Liu                     BMCWEB_LOG_ERROR << "DBUS response error" << ec.value();
74a7210020SGeorge Liu                     messages::internalError(asyncResp->res);
75a7210020SGeorge Liu                 }
76a7210020SGeorge Liu                 return;
77a7210020SGeorge Liu             }
78a7210020SGeorge Liu 
79a7210020SGeorge Liu             for (const auto& endpoint : endpoints)
80a7210020SGeorge Liu             {
81a7210020SGeorge Liu                 updatePowerSupplyList(asyncResp, chassisId, endpoint);
82a7210020SGeorge Liu             }
83a7210020SGeorge Liu         });
84a7210020SGeorge Liu }
85a7210020SGeorge Liu 
86a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead(
87a7210020SGeorge Liu     App& app, const crow::Request& req,
88a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
89a7210020SGeorge Liu     const std::string& chassisId)
90a7210020SGeorge Liu {
91a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
92a7210020SGeorge Liu     {
93a7210020SGeorge Liu         return;
94a7210020SGeorge Liu     }
95a7210020SGeorge Liu 
96a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
97a7210020SGeorge Liu         asyncResp, chassisId,
98a7210020SGeorge Liu         [asyncResp,
99a7210020SGeorge Liu          chassisId](const std::optional<std::string>& validChassisPath) {
100a7210020SGeorge Liu         if (!validChassisPath)
101a7210020SGeorge Liu         {
102a7210020SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
103a7210020SGeorge Liu             return;
104a7210020SGeorge Liu         }
105a7210020SGeorge Liu         asyncResp->res.addHeader(
106a7210020SGeorge Liu             boost::beast::http::field::link,
107a7210020SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
108a7210020SGeorge Liu         });
109a7210020SGeorge Liu }
110a7210020SGeorge Liu 
111a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet(
112a7210020SGeorge Liu     App& app, const crow::Request& req,
113a7210020SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
114a7210020SGeorge Liu     const std::string& chassisId)
115a7210020SGeorge Liu {
116a7210020SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
117a7210020SGeorge Liu     {
118a7210020SGeorge Liu         return;
119a7210020SGeorge Liu     }
120a7210020SGeorge Liu 
121a7210020SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
122a7210020SGeorge Liu         asyncResp, chassisId,
123a7210020SGeorge Liu         std::bind_front(doPowerSupplyCollection, asyncResp, chassisId));
124a7210020SGeorge Liu }
125a7210020SGeorge Liu 
126a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app)
127a7210020SGeorge Liu {
128a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
129a7210020SGeorge Liu         .privileges(redfish::privileges::headPowerSupplyCollection)
130a7210020SGeorge Liu         .methods(boost::beast::http::verb::head)(
131a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
132a7210020SGeorge Liu 
133a7210020SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
134a7210020SGeorge Liu         .privileges(redfish::privileges::getPowerSupplyCollection)
135a7210020SGeorge Liu         .methods(boost::beast::http::verb::get)(
136a7210020SGeorge Liu             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
137a7210020SGeorge Liu }
138a7210020SGeorge Liu 
139*00ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath,
140*00ef5dc6SGeorge Liu                                const std::string& powerSupplyId)
141*00ef5dc6SGeorge Liu {
142*00ef5dc6SGeorge Liu     std::string powerSupplyName =
143*00ef5dc6SGeorge Liu         sdbusplus::message::object_path(powerSupplyPath).filename();
144*00ef5dc6SGeorge Liu 
145*00ef5dc6SGeorge Liu     return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId);
146*00ef5dc6SGeorge Liu }
147*00ef5dc6SGeorge Liu 
148*00ef5dc6SGeorge Liu inline void
149*00ef5dc6SGeorge Liu     getValidPowerSupplyPath(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150*00ef5dc6SGeorge Liu                             const std::string& validChassisPath,
151*00ef5dc6SGeorge Liu                             const std::string& powerSupplyId,
152*00ef5dc6SGeorge Liu                             std::function<void()>&& callback)
153*00ef5dc6SGeorge Liu {
154*00ef5dc6SGeorge Liu     std::string powerPath = validChassisPath + "/powered_by";
155*00ef5dc6SGeorge Liu     dbus::utility::getAssociationEndPoints(
156*00ef5dc6SGeorge Liu         powerPath, [asyncResp, powerSupplyId, callback{std::move(callback)}](
157*00ef5dc6SGeorge Liu                        const boost::system::error_code& ec,
158*00ef5dc6SGeorge Liu                        const dbus::utility::MapperEndPoints& endpoints) {
159*00ef5dc6SGeorge Liu             if (ec)
160*00ef5dc6SGeorge Liu             {
161*00ef5dc6SGeorge Liu                 if (ec.value() != EBADR)
162*00ef5dc6SGeorge Liu                 {
163*00ef5dc6SGeorge Liu                     BMCWEB_LOG_ERROR
164*00ef5dc6SGeorge Liu                         << "DBUS response error for getAssociationEndPoints"
165*00ef5dc6SGeorge Liu                         << ec.value();
166*00ef5dc6SGeorge Liu                     messages::internalError(asyncResp->res);
167*00ef5dc6SGeorge Liu                     return;
168*00ef5dc6SGeorge Liu                 }
169*00ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
170*00ef5dc6SGeorge Liu                                            powerSupplyId);
171*00ef5dc6SGeorge Liu                 return;
172*00ef5dc6SGeorge Liu             }
173*00ef5dc6SGeorge Liu 
174*00ef5dc6SGeorge Liu             for (const auto& endpoint : endpoints)
175*00ef5dc6SGeorge Liu             {
176*00ef5dc6SGeorge Liu                 if (checkPowerSupplyId(endpoint, powerSupplyId))
177*00ef5dc6SGeorge Liu                 {
178*00ef5dc6SGeorge Liu                     callback();
179*00ef5dc6SGeorge Liu                     return;
180*00ef5dc6SGeorge Liu                 }
181*00ef5dc6SGeorge Liu             }
182*00ef5dc6SGeorge Liu 
183*00ef5dc6SGeorge Liu             if (!endpoints.empty())
184*00ef5dc6SGeorge Liu             {
185*00ef5dc6SGeorge Liu                 BMCWEB_LOG_WARNING << "Power supply not found: "
186*00ef5dc6SGeorge Liu                                    << powerSupplyId;
187*00ef5dc6SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "PowerSupplies",
188*00ef5dc6SGeorge Liu                                            powerSupplyId);
189*00ef5dc6SGeorge Liu                 return;
190*00ef5dc6SGeorge Liu             }
191*00ef5dc6SGeorge Liu         });
192*00ef5dc6SGeorge Liu }
193*00ef5dc6SGeorge Liu 
194*00ef5dc6SGeorge Liu inline void
195*00ef5dc6SGeorge Liu     doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196*00ef5dc6SGeorge Liu                      const std::string& chassisId,
197*00ef5dc6SGeorge Liu                      const std::string& powerSupplyId,
198*00ef5dc6SGeorge Liu                      const std::optional<std::string>& validChassisPath)
199*00ef5dc6SGeorge Liu {
200*00ef5dc6SGeorge Liu     if (!validChassisPath)
201*00ef5dc6SGeorge Liu     {
202*00ef5dc6SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
203*00ef5dc6SGeorge Liu         return;
204*00ef5dc6SGeorge Liu     }
205*00ef5dc6SGeorge Liu 
206*00ef5dc6SGeorge Liu     // Get the correct Path and Service that match the input parameters
207*00ef5dc6SGeorge Liu     getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
208*00ef5dc6SGeorge Liu                             [asyncResp, chassisId, powerSupplyId]() {
209*00ef5dc6SGeorge Liu         asyncResp->res.addHeader(
210*00ef5dc6SGeorge Liu             boost::beast::http::field::link,
211*00ef5dc6SGeorge Liu             "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
212*00ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.type"] =
213*00ef5dc6SGeorge Liu             "#PowerSupply.v1_5_0.PowerSupply";
214*00ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Name"] = "Power Supply";
215*00ef5dc6SGeorge Liu         asyncResp->res.jsonValue["Id"] = powerSupplyId;
216*00ef5dc6SGeorge Liu         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
217*00ef5dc6SGeorge Liu             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
218*00ef5dc6SGeorge Liu             powerSupplyId);
219*00ef5dc6SGeorge Liu     });
220*00ef5dc6SGeorge Liu }
221*00ef5dc6SGeorge Liu 
222*00ef5dc6SGeorge Liu inline void
223*00ef5dc6SGeorge Liu     handlePowerSupplyHead(App& app, const crow::Request& req,
224*00ef5dc6SGeorge Liu                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
225*00ef5dc6SGeorge Liu                           const std::string& chassisId,
226*00ef5dc6SGeorge Liu                           const std::string& powerSupplyId)
227*00ef5dc6SGeorge Liu {
228*00ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
229*00ef5dc6SGeorge Liu     {
230*00ef5dc6SGeorge Liu         return;
231*00ef5dc6SGeorge Liu     }
232*00ef5dc6SGeorge Liu 
233*00ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
234*00ef5dc6SGeorge Liu         asyncResp, chassisId,
235*00ef5dc6SGeorge Liu         [asyncResp, chassisId,
236*00ef5dc6SGeorge Liu          powerSupplyId](const std::optional<std::string>& validChassisPath) {
237*00ef5dc6SGeorge Liu         if (!validChassisPath)
238*00ef5dc6SGeorge Liu         {
239*00ef5dc6SGeorge Liu             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
240*00ef5dc6SGeorge Liu             return;
241*00ef5dc6SGeorge Liu         }
242*00ef5dc6SGeorge Liu 
243*00ef5dc6SGeorge Liu         // Get the correct Path and Service that match the input parameters
244*00ef5dc6SGeorge Liu         getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId,
245*00ef5dc6SGeorge Liu                                 [asyncResp]() {
246*00ef5dc6SGeorge Liu             asyncResp->res.addHeader(
247*00ef5dc6SGeorge Liu                 boost::beast::http::field::link,
248*00ef5dc6SGeorge Liu                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
249*00ef5dc6SGeorge Liu         });
250*00ef5dc6SGeorge Liu         });
251*00ef5dc6SGeorge Liu }
252*00ef5dc6SGeorge Liu 
253*00ef5dc6SGeorge Liu inline void
254*00ef5dc6SGeorge Liu     handlePowerSupplyGet(App& app, const crow::Request& req,
255*00ef5dc6SGeorge Liu                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
256*00ef5dc6SGeorge Liu                          const std::string& chassisId,
257*00ef5dc6SGeorge Liu                          const std::string& powerSupplyId)
258*00ef5dc6SGeorge Liu {
259*00ef5dc6SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
260*00ef5dc6SGeorge Liu     {
261*00ef5dc6SGeorge Liu         return;
262*00ef5dc6SGeorge Liu     }
263*00ef5dc6SGeorge Liu 
264*00ef5dc6SGeorge Liu     redfish::chassis_utils::getValidChassisPath(
265*00ef5dc6SGeorge Liu         asyncResp, chassisId,
266*00ef5dc6SGeorge Liu         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
267*00ef5dc6SGeorge Liu }
268*00ef5dc6SGeorge Liu 
269*00ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app)
270*00ef5dc6SGeorge Liu {
271*00ef5dc6SGeorge Liu     BMCWEB_ROUTE(
272*00ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
273*00ef5dc6SGeorge Liu         .privileges(redfish::privileges::headPowerSupply)
274*00ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::head)(
275*00ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyHead, std::ref(app)));
276*00ef5dc6SGeorge Liu 
277*00ef5dc6SGeorge Liu     BMCWEB_ROUTE(
278*00ef5dc6SGeorge Liu         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
279*00ef5dc6SGeorge Liu         .privileges(redfish::privileges::getPowerSupply)
280*00ef5dc6SGeorge Liu         .methods(boost::beast::http::verb::get)(
281*00ef5dc6SGeorge Liu             std::bind_front(handlePowerSupplyGet, std::ref(app)));
282*00ef5dc6SGeorge Liu }
283*00ef5dc6SGeorge Liu 
284a7210020SGeorge Liu } // namespace redfish
285