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