xref: /openbmc/bmcweb/redfish-core/lib/power_supply.hpp (revision 7066dc58dd7c3b56e0f224458e9190be8d758771)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #pragma once
4 
5 #include "app.hpp"
6 #include "async_resp.hpp"
7 #include "dbus_utility.hpp"
8 #include "error_messages.hpp"
9 #include "generated/enums/resource.hpp"
10 #include "http_request.hpp"
11 #include "led.hpp"
12 #include "logging.hpp"
13 #include "query.hpp"
14 #include "registries/privilege_registry.hpp"
15 #include "utils/chassis_utils.hpp"
16 #include "utils/dbus_utils.hpp"
17 #include "utils/json_utils.hpp"
18 #include "utils/time_utils.hpp"
19 
20 #include <asm-generic/errno.h>
21 
22 #include <boost/beast/http/field.hpp>
23 #include <boost/beast/http/verb.hpp>
24 #include <boost/system/error_code.hpp>
25 #include <boost/url/format.hpp>
26 #include <nlohmann/json.hpp>
27 #include <sdbusplus/unpack_properties.hpp>
28 
29 #include <array>
30 #include <cstdint>
31 #include <functional>
32 #include <memory>
33 #include <optional>
34 #include <string>
35 #include <string_view>
36 #include <utility>
37 
38 namespace redfish
39 {
40 
41 static constexpr std::array<std::string_view, 1> powerSupplyInterface = {
42     "xyz.openbmc_project.Inventory.Item.PowerSupply"};
43 
updatePowerSupplyList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const dbus::utility::MapperGetSubTreePathsResponse & powerSupplyPaths)44 inline void updatePowerSupplyList(
45     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46     const std::string& chassisId,
47     const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths)
48 {
49     nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"];
50     for (const std::string& powerSupplyPath : powerSupplyPaths)
51     {
52         std::string powerSupplyName =
53             sdbusplus::message::object_path(powerSupplyPath).filename();
54         if (powerSupplyName.empty())
55         {
56             continue;
57         }
58 
59         nlohmann::json item = nlohmann::json::object();
60         item["@odata.id"] = boost::urls::format(
61             "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
62             powerSupplyName);
63 
64         powerSupplyList.emplace_back(std::move(item));
65     }
66     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
67 }
68 
doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & subtreePaths)69 inline void doPowerSupplyCollection(
70     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
71     const std::string& chassisId, const boost::system::error_code& ec,
72     const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
73 {
74     if (ec)
75     {
76         if (ec.value() == boost::system::errc::io_error)
77         {
78             BMCWEB_LOG_WARNING("Chassis not found");
79             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
80             return;
81         }
82         if (ec.value() != EBADR)
83         {
84             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
85             messages::internalError(asyncResp->res);
86         }
87         return;
88     }
89     asyncResp->res.addHeader(
90         boost::beast::http::field::link,
91         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
92     asyncResp->res.jsonValue["@odata.type"] =
93         "#PowerSupplyCollection.PowerSupplyCollection";
94     asyncResp->res.jsonValue["Name"] = "Power Supply Collection";
95     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
96         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId);
97     asyncResp->res.jsonValue["Description"] =
98         "The collection of PowerSupply resource instances.";
99     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
100     asyncResp->res.jsonValue["Members@odata.count"] = 0;
101 
102     updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
103 }
104 
handlePowerSupplyCollectionHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)105 inline void handlePowerSupplyCollectionHead(
106     App& app, const crow::Request& req,
107     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
108     const std::string& chassisId)
109 {
110     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111     {
112         return;
113     }
114 
115     redfish::chassis_utils::getValidChassisPath(
116         asyncResp, chassisId,
117         [asyncResp,
118          chassisId](const std::optional<std::string>& validChassisPath) {
119             if (!validChassisPath)
120             {
121                 BMCWEB_LOG_WARNING("Chassis not found");
122                 messages::resourceNotFound(asyncResp->res, "Chassis",
123                                            chassisId);
124                 return;
125             }
126             asyncResp->res.addHeader(
127                 boost::beast::http::field::link,
128                 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
129         });
130 }
131 
handlePowerSupplyCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)132 inline void handlePowerSupplyCollectionGet(
133     App& app, const crow::Request& req,
134     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
135     const std::string& chassisId)
136 {
137     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
138     {
139         return;
140     }
141 
142     const std::string reqpath = "/xyz/openbmc_project/inventory";
143 
144     dbus::utility::getAssociatedSubTreePathsById(
145         chassisId, reqpath, chassisInterfaces, "powered_by",
146         powerSupplyInterface,
147         [asyncResp, chassisId](
148             const boost::system::error_code& ec,
149             const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
150             doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
151         });
152 }
153 
requestRoutesPowerSupplyCollection(App & app)154 inline void requestRoutesPowerSupplyCollection(App& app)
155 {
156     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
157         .privileges(redfish::privileges::headPowerSupplyCollection)
158         .methods(boost::beast::http::verb::head)(
159             std::bind_front(handlePowerSupplyCollectionHead, std::ref(app)));
160 
161     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/")
162         .privileges(redfish::privileges::getPowerSupplyCollection)
163         .methods(boost::beast::http::verb::get)(
164             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
165 }
166 
afterGetValidPowerSupplyPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & powerSupplyId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree,const std::function<void (const std::string & powerSupplyPath,const std::string & service)> & callback)167 inline void afterGetValidPowerSupplyPath(
168     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
169     const std::string& powerSupplyId, const boost::system::error_code& ec,
170     const dbus::utility::MapperGetSubTreeResponse& subtree,
171     const std::function<void(const std::string& powerSupplyPath,
172                              const std::string& service)>& callback)
173 {
174     if (ec)
175     {
176         if (ec.value() == boost::system::errc::io_error)
177         {
178             // Not found
179             callback(std::string(), std::string());
180             return;
181         }
182         if (ec.value() != EBADR)
183         {
184             BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
185             messages::internalError(asyncResp->res);
186             return;
187         }
188         callback(std::string(), std::string());
189         return;
190     }
191     for (const auto& [objectPath, service] : subtree)
192     {
193         sdbusplus::message::object_path path(objectPath);
194         if (path.filename() == powerSupplyId)
195         {
196             callback(path, service.begin()->first);
197             return;
198         }
199     }
200 
201     BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
202     messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
203 }
204 
getValidPowerSupplyPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & powerSupplyId,std::function<void (const std::string & powerSupplyPath,const std::string & service)> && callback)205 inline void getValidPowerSupplyPath(
206     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
207     const std::string& chassisId, const std::string& powerSupplyId,
208     std::function<void(const std::string& powerSupplyPath,
209                        const std::string& service)>&& callback)
210 {
211     const std::string reqpath = "/xyz/openbmc_project/inventory";
212 
213     dbus::utility::getAssociatedSubTreeById(
214         chassisId, reqpath, chassisInterfaces, "powered_by",
215         powerSupplyInterface,
216         [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
217             const boost::system::error_code& ec,
218             const dbus::utility::MapperGetSubTreeResponse& subtree) {
219             afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
220                                          callback);
221         });
222 }
223 
getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)224 inline void getPowerSupplyState(
225     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
226     const std::string& service, const std::string& path)
227 {
228     dbus::utility::getProperty<bool>(
229         service, path, "xyz.openbmc_project.Inventory.Item", "Present",
230         [asyncResp](const boost::system::error_code& ec, const bool value) {
231             if (ec)
232             {
233                 if (ec.value() != EBADR)
234                 {
235                     BMCWEB_LOG_ERROR("DBUS response error for State {}",
236                                      ec.value());
237                     messages::internalError(asyncResp->res);
238                 }
239                 return;
240             }
241 
242             if (!value)
243             {
244                 asyncResp->res.jsonValue["Status"]["State"] =
245                     resource::State::Absent;
246             }
247         });
248 }
249 
getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)250 inline void getPowerSupplyHealth(
251     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
252     const std::string& service, const std::string& path)
253 {
254     dbus::utility::getProperty<bool>(
255         service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus",
256         "Functional",
257         [asyncResp](const boost::system::error_code& ec, const bool value) {
258             if (ec)
259             {
260                 if (ec.value() != EBADR)
261                 {
262                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
263                                      ec.value());
264                     messages::internalError(asyncResp->res);
265                 }
266                 return;
267             }
268 
269             if (!value)
270             {
271                 asyncResp->res.jsonValue["Status"]["Health"] =
272                     resource::Health::Critical;
273             }
274         });
275 }
276 
getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)277 inline void getPowerSupplyAsset(
278     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279     const std::string& service, const std::string& path)
280 {
281     dbus::utility::getAllProperties(
282         service, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
283         [asyncResp](const boost::system::error_code& ec,
284                     const dbus::utility::DBusPropertiesMap& propertiesList) {
285             if (ec)
286             {
287                 if (ec.value() != EBADR)
288                 {
289                     BMCWEB_LOG_ERROR("DBUS response error for Asset {}",
290                                      ec.value());
291                     messages::internalError(asyncResp->res);
292                 }
293                 return;
294             }
295 
296             const std::string* partNumber = nullptr;
297             const std::string* serialNumber = nullptr;
298             const std::string* manufacturer = nullptr;
299             const std::string* model = nullptr;
300             const std::string* sparePartNumber = nullptr;
301             const std::string* buildDate = nullptr;
302 
303             const bool success = sdbusplus::unpackPropertiesNoThrow(
304                 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
305                 partNumber, "SerialNumber", serialNumber, "Manufacturer",
306                 manufacturer, "Model", model, "SparePartNumber",
307                 sparePartNumber, "BuildDate", buildDate);
308 
309             if (!success)
310             {
311                 messages::internalError(asyncResp->res);
312                 return;
313             }
314 
315             if (partNumber != nullptr)
316             {
317                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
318             }
319 
320             if (serialNumber != nullptr)
321             {
322                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
323             }
324 
325             if (manufacturer != nullptr)
326             {
327                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
328             }
329 
330             if (model != nullptr)
331             {
332                 asyncResp->res.jsonValue["Model"] = *model;
333             }
334 
335             // SparePartNumber is optional on D-Bus so skip if it is empty
336             if (sparePartNumber != nullptr && !sparePartNumber->empty())
337             {
338                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
339             }
340 
341             if (buildDate != nullptr)
342             {
343                 time_utils::productionDateReport(asyncResp->res, *buildDate);
344             }
345         });
346 }
347 
getPowerSupplyFirmwareVersion(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)348 inline void getPowerSupplyFirmwareVersion(
349     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
350     const std::string& service, const std::string& path)
351 {
352     dbus::utility::getProperty<std::string>(
353         service, path, "xyz.openbmc_project.Software.Version", "Version",
354         [asyncResp](const boost::system::error_code& ec,
355                     const std::string& value) {
356             if (ec)
357             {
358                 if (ec.value() != EBADR)
359                 {
360                     BMCWEB_LOG_ERROR(
361                         "DBUS response error for FirmwareVersion {}",
362                         ec.value());
363                     messages::internalError(asyncResp->res);
364                 }
365                 return;
366             }
367             asyncResp->res.jsonValue["FirmwareVersion"] = value;
368         });
369 }
370 
getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)371 inline void getPowerSupplyLocation(
372     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
373     const std::string& service, const std::string& path)
374 {
375     dbus::utility::getProperty<std::string>(
376         service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode",
377         "LocationCode",
378         [asyncResp](const boost::system::error_code& ec,
379                     const std::string& value) {
380             if (ec)
381             {
382                 if (ec.value() != EBADR)
383                 {
384                     BMCWEB_LOG_ERROR("DBUS response error for Location {}",
385                                      ec.value());
386                     messages::internalError(asyncResp->res);
387                 }
388                 return;
389             }
390             asyncResp->res
391                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value;
392         });
393 }
394 
handleGetEfficiencyResponse(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,uint32_t value)395 inline void handleGetEfficiencyResponse(
396     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
397     const boost::system::error_code& ec, uint32_t value)
398 {
399     if (ec)
400     {
401         if (ec.value() != EBADR)
402         {
403             BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}",
404                              ec.value());
405             messages::internalError(asyncResp->res);
406         }
407         return;
408     }
409     // The PDI default value is 0, if it hasn't been set leave off
410     if (value == 0)
411     {
412         return;
413     }
414 
415     nlohmann::json::array_t efficiencyRatings;
416     nlohmann::json::object_t efficiencyPercent;
417     efficiencyPercent["EfficiencyPercent"] = value;
418     efficiencyRatings.emplace_back(std::move(efficiencyPercent));
419     asyncResp->res.jsonValue["EfficiencyRatings"] =
420         std::move(efficiencyRatings);
421 }
422 
handlePowerSupplyAttributesSubTreeResponse(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)423 inline void handlePowerSupplyAttributesSubTreeResponse(
424     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
425     const boost::system::error_code& ec,
426     const dbus::utility::MapperGetSubTreeResponse& subtree)
427 {
428     if (ec)
429     {
430         if (ec.value() != EBADR)
431         {
432             BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}",
433                              ec.value());
434             messages::internalError(asyncResp->res);
435         }
436         return;
437     }
438 
439     if (subtree.empty())
440     {
441         BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!");
442         return;
443     }
444 
445     if (subtree.size() != 1)
446     {
447         BMCWEB_LOG_ERROR(
448             "Unexpected number of paths returned by getSubTree: {}",
449             subtree.size());
450         messages::internalError(asyncResp->res);
451         return;
452     }
453 
454     const auto& [path, serviceMap] = *subtree.begin();
455     const auto& [service, interfaces] = *serviceMap.begin();
456     dbus::utility::getProperty<uint32_t>(
457         service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes",
458         "DeratingFactor",
459         [asyncResp](const boost::system::error_code& ec1, uint32_t value) {
460             handleGetEfficiencyResponse(asyncResp, ec1, value);
461         });
462 }
463 
getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)464 inline void getEfficiencyPercent(
465     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
466 {
467     constexpr std::array<std::string_view, 1> efficiencyIntf = {
468         "xyz.openbmc_project.Control.PowerSupplyAttributes"};
469 
470     dbus::utility::getSubTree(
471         "/xyz/openbmc_project", 0, efficiencyIntf,
472         [asyncResp](const boost::system::error_code& ec,
473                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
474             handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree);
475         });
476 }
477 
doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & powerSupplyId,const std::string & powerSupplyPath,const std::string & service)478 inline void doPowerSupplyGet(
479     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
480     const std::string& chassisId, const std::string& powerSupplyId,
481     const std::string& powerSupplyPath, const std::string& service)
482 {
483     if (powerSupplyPath.empty() || service.empty())
484     {
485         BMCWEB_LOG_WARNING("PowerSupply not found");
486         messages::resourceNotFound(asyncResp->res, "PowerSupply",
487                                    powerSupplyId);
488         return;
489     }
490 
491     asyncResp->res.addHeader(
492         boost::beast::http::field::link,
493         "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
494     asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
495     asyncResp->res.jsonValue["Name"] = "Power Supply";
496     asyncResp->res.jsonValue["Id"] = powerSupplyId;
497     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
498         "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
499         powerSupplyId);
500 
501     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
502     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
503 
504     getPowerSupplyState(asyncResp, service, powerSupplyPath);
505     getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
506     getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
507     getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
508     getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
509     getEfficiencyPercent(asyncResp);
510     getLocationIndicatorActive(asyncResp, powerSupplyPath);
511 }
512 
handlePowerSupplyHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & powerSupplyId)513 inline void handlePowerSupplyHead(
514     App& app, const crow::Request& req,
515     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516     const std::string& chassisId, const std::string& powerSupplyId)
517 {
518     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
519     {
520         return;
521     }
522 
523     // Get the correct Path and Service that match the input parameters
524     getValidPowerSupplyPath(
525         asyncResp, chassisId, powerSupplyId,
526         [asyncResp, powerSupplyId](const std::string& powerSupplyPath,
527                                    const std::string& service) {
528             if (powerSupplyPath.empty() || service.empty())
529             {
530                 BMCWEB_LOG_WARNING("PowerSupply not found");
531                 messages::resourceNotFound(asyncResp->res, "PowerSupply",
532                                            powerSupplyId);
533                 return;
534             }
535             asyncResp->res.addHeader(
536                 boost::beast::http::field::link,
537                 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
538         });
539 }
540 
handlePowerSupplyGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & powerSupplyId)541 inline void handlePowerSupplyGet(
542     App& app, const crow::Request& req,
543     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
544     const std::string& chassisId, const std::string& powerSupplyId)
545 {
546     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
547     {
548         return;
549     }
550     getValidPowerSupplyPath(
551         asyncResp, chassisId, powerSupplyId,
552         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
553 }
554 
doPatchPowerSupply(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool locationIndicatorActive,const std::string & powerSupplyPath,const std::string &)555 inline void doPatchPowerSupply(
556     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
557     const bool locationIndicatorActive, const std::string& powerSupplyPath,
558     const std::string& /*service*/)
559 {
560     setLocationIndicatorActive(asyncResp, powerSupplyPath,
561                                locationIndicatorActive);
562 }
563 
handlePowerSupplyPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & powerSupplyId)564 inline void handlePowerSupplyPatch(
565     App& app, const crow::Request& req,
566     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567     const std::string& chassisId, const std::string& powerSupplyId)
568 {
569     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
570     {
571         return;
572     }
573 
574     std::optional<bool> locationIndicatorActive;
575     if (!json_util::readJsonPatch(                             //
576             req, asyncResp->res,                               //
577             "LocationIndicatorActive", locationIndicatorActive //
578             ))
579     {
580         return;
581     }
582 
583     if (locationIndicatorActive)
584     {
585         // Get the correct power supply Path that match the input parameters
586         getValidPowerSupplyPath(asyncResp, chassisId, powerSupplyId,
587                                 std::bind_front(doPatchPowerSupply, asyncResp,
588                                                 *locationIndicatorActive));
589     }
590 }
591 
requestRoutesPowerSupply(App & app)592 inline void requestRoutesPowerSupply(App& app)
593 {
594     BMCWEB_ROUTE(
595         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
596         .privileges(redfish::privileges::headPowerSupply)
597         .methods(boost::beast::http::verb::head)(
598             std::bind_front(handlePowerSupplyHead, std::ref(app)));
599 
600     BMCWEB_ROUTE(
601         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
602         .privileges(redfish::privileges::getPowerSupply)
603         .methods(boost::beast::http::verb::get)(
604             std::bind_front(handlePowerSupplyGet, std::ref(app)));
605 
606     BMCWEB_ROUTE(
607         app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/")
608         .privileges(redfish::privileges::patchPowerSupply)
609         .methods(boost::beast::http::verb::patch)(
610             std::bind_front(handlePowerSupplyPatch, std::ref(app)));
611 }
612 
613 } // namespace redfish
614