xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 168e20c1306e3e689907ba43e14ea679e2328611)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "health.hpp"
19 #include "led.hpp"
20 
21 #include <app.hpp>
22 #include <boost/container/flat_map.hpp>
23 #include <dbus_utility.hpp>
24 #include <registries/privilege_registry.hpp>
25 #include <utils/collection.hpp>
26 
27 namespace redfish
28 {
29 
30 /**
31  * @brief Retrieves chassis state properties over dbus
32  *
33  * @param[in] aResp - Shared pointer for completing asynchronous calls.
34  *
35  * @return None.
36  */
37 inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp)
38 {
39     crow::connections::systemBus->async_method_call(
40         [aResp{std::move(aResp)}](
41             const boost::system::error_code ec,
42             const dbus::utility::DbusVariantType& chassisState) {
43             if (ec)
44             {
45                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
46                 messages::internalError(aResp->res);
47                 return;
48             }
49 
50             const std::string* s = std::get_if<std::string>(&chassisState);
51             BMCWEB_LOG_DEBUG << "Chassis state: " << *s;
52             if (s != nullptr)
53             {
54                 // Verify Chassis State
55                 if (*s == "xyz.openbmc_project.State.Chassis.PowerState.On")
56                 {
57                     aResp->res.jsonValue["PowerState"] = "On";
58                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
59                 }
60                 else if (*s ==
61                          "xyz.openbmc_project.State.Chassis.PowerState.Off")
62                 {
63                     aResp->res.jsonValue["PowerState"] = "Off";
64                     aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
65                 }
66             }
67         },
68         "xyz.openbmc_project.State.Chassis",
69         "/xyz/openbmc_project/state/chassis0",
70         "org.freedesktop.DBus.Properties", "Get",
71         "xyz.openbmc_project.State.Chassis", "CurrentPowerState");
72 }
73 
74 /**
75  * DBus types primitives for several generic DBus interfaces
76  * TODO(Pawel) consider move this to separate file into boost::dbus
77  */
78 using ManagedObjectsType = std::vector<std::pair<
79     sdbusplus::message::object_path,
80     std::vector<std::pair<
81         std::string,
82         std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>>>>>;
83 
84 using PropertiesType =
85     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>;
86 
87 inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
88                                   const std::string& service,
89                                   const std::string& objPath)
90 {
91     BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
92 
93     crow::connections::systemBus->async_method_call(
94         [aResp{std::move(aResp)}](const boost::system::error_code ec,
95                                   const dbus::utility::DbusVariantType& value) {
96             if (ec)
97             {
98                 // do not add err msg in redfish response, because this is not
99                 //     mandatory property
100                 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
101                 return;
102             }
103 
104             const std::string* status = std::get_if<std::string>(&value);
105 
106             if (status == nullptr)
107             {
108                 BMCWEB_LOG_ERROR << "intrusion status read error \n";
109                 return;
110             }
111 
112             aResp->res.jsonValue["PhysicalSecurity"] = {
113                 {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}};
114         },
115         service, objPath, "org.freedesktop.DBus.Properties", "Get",
116         "xyz.openbmc_project.Chassis.Intrusion", "Status");
117 }
118 
119 /**
120  * Retrieves physical security properties over dbus
121  */
122 inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp)
123 {
124     crow::connections::systemBus->async_method_call(
125         [aResp{std::move(aResp)}](
126             const boost::system::error_code ec,
127             const std::vector<std::pair<
128                 std::string,
129                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
130                 subtree) {
131             if (ec)
132             {
133                 // do not add err msg in redfish response, because this is not
134                 //     mandatory property
135                 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec
136                                 << "\n";
137                 return;
138             }
139             // Iterate over all retrieved ObjectPaths.
140             for (const auto& object : subtree)
141             {
142                 for (const auto& service : object.second)
143                 {
144                     getIntrusionByService(aResp, service.first, object.first);
145                     return;
146                 }
147             }
148         },
149         "xyz.openbmc_project.ObjectMapper",
150         "/xyz/openbmc_project/object_mapper",
151         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
152         "/xyz/openbmc_project/Intrusion", 1,
153         std::array<const char*, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
154 }
155 
156 /**
157  * ChassisCollection derived class for delivering Chassis Collection Schema
158  *  Functions triggers appropriate requests on DBus
159  */
160 inline void requestRoutesChassisCollection(App& app)
161 {
162     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
163         .privileges(redfish::privileges::getChassisCollection)
164         .methods(boost::beast::http::verb::get)(
165             [](const crow::Request&,
166                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
167                 asyncResp->res.jsonValue["@odata.type"] =
168                     "#ChassisCollection.ChassisCollection";
169                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
170                 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
171 
172                 collection_util::getCollectionMembers(
173                     asyncResp, "/redfish/v1/Chassis",
174                     {"xyz.openbmc_project.Inventory.Item.Board",
175                      "xyz.openbmc_project.Inventory.Item.Chassis"});
176             });
177 }
178 
179 inline void
180     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181                            const std::string& connectionName,
182                            const std::string& path)
183 {
184     crow::connections::systemBus->async_method_call(
185         [asyncResp](const boost::system::error_code ec,
186                     const dbus::utility::DbusVariantType& property) {
187             if (ec)
188             {
189                 BMCWEB_LOG_DEBUG << "DBUS response error for Location";
190                 messages::internalError(asyncResp->res);
191                 return;
192             }
193 
194             const std::string* value = std::get_if<std::string>(&property);
195             if (value == nullptr)
196             {
197                 BMCWEB_LOG_DEBUG << "Null value returned for locaton code";
198                 messages::internalError(asyncResp->res);
199                 return;
200             }
201             asyncResp->res
202                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = *value;
203         },
204         connectionName, path, "org.freedesktop.DBus.Properties", "Get",
205         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
206 }
207 
208 inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
209                            const std::string& connectionName,
210                            const std::string& path)
211 {
212     crow::connections::systemBus->async_method_call(
213         [asyncResp](const boost::system::error_code ec,
214                     const dbus::utility::DbusVariantType& chassisUUID) {
215             if (ec)
216             {
217                 BMCWEB_LOG_DEBUG << "DBUS response error for UUID";
218                 messages::internalError(asyncResp->res);
219                 return;
220             }
221             const std::string* value = std::get_if<std::string>(&chassisUUID);
222             if (value == nullptr)
223             {
224                 BMCWEB_LOG_DEBUG << "Null value returned for UUID";
225                 messages::internalError(asyncResp->res);
226                 return;
227             }
228             asyncResp->res.jsonValue["UUID"] = *value;
229         },
230         connectionName, path, "org.freedesktop.DBus.Properties", "Get",
231         "xyz.openbmc_project.Common.UUID", "UUID");
232 }
233 
234 /**
235  * Chassis override class for delivering Chassis Schema
236  * Functions triggers appropriate requests on DBus
237  */
238 inline void requestRoutesChassis(App& app)
239 {
240     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
241         .privileges(redfish::privileges::getChassis)
242         .methods(
243             boost::beast::http::verb::get)([](const crow::Request&,
244                                               const std::shared_ptr<
245                                                   bmcweb::AsyncResp>& asyncResp,
246                                               const std::string& chassisId) {
247             const std::array<const char*, 2> interfaces = {
248                 "xyz.openbmc_project.Inventory.Item.Board",
249                 "xyz.openbmc_project.Inventory.Item.Chassis"};
250 
251             crow::connections::systemBus->async_method_call(
252                 [asyncResp, chassisId(std::string(chassisId))](
253                     const boost::system::error_code ec,
254                     const crow::openbmc_mapper::GetSubTreeType& subtree) {
255                     if (ec)
256                     {
257                         messages::internalError(asyncResp->res);
258                         return;
259                     }
260                     // Iterate over all retrieved ObjectPaths.
261                     for (const std::pair<
262                              std::string,
263                              std::vector<std::pair<std::string,
264                                                    std::vector<std::string>>>>&
265                              object : subtree)
266                     {
267                         const std::string& path = object.first;
268                         const std::vector<
269                             std::pair<std::string, std::vector<std::string>>>&
270                             connectionNames = object.second;
271 
272                         sdbusplus::message::object_path objPath(path);
273                         if (objPath.filename() != chassisId)
274                         {
275                             continue;
276                         }
277 
278                         auto health =
279                             std::make_shared<HealthPopulate>(asyncResp);
280 
281                         crow::connections::systemBus->async_method_call(
282                             [health](const boost::system::error_code ec2,
283                                      dbus::utility::DbusVariantType& resp) {
284                                 if (ec2)
285                                 {
286                                     return; // no sensors = no failures
287                                 }
288                                 std::vector<std::string>* data =
289                                     std::get_if<std::vector<std::string>>(
290                                         &resp);
291                                 if (data == nullptr)
292                                 {
293                                     return;
294                                 }
295                                 health->inventory = std::move(*data);
296                             },
297                             "xyz.openbmc_project.ObjectMapper",
298                             path + "/all_sensors",
299                             "org.freedesktop.DBus.Properties", "Get",
300                             "xyz.openbmc_project.Association", "endpoints");
301 
302                         health->populate();
303 
304                         if (connectionNames.size() < 1)
305                         {
306                             BMCWEB_LOG_ERROR << "Got 0 Connection names";
307                             continue;
308                         }
309 
310                         asyncResp->res.jsonValue["@odata.type"] =
311                             "#Chassis.v1_14_0.Chassis";
312                         asyncResp->res.jsonValue["@odata.id"] =
313                             "/redfish/v1/Chassis/" + chassisId;
314                         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
315                         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
316                         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] =
317                             {{"target", "/redfish/v1/Chassis/" + chassisId +
318                                             "/Actions/Chassis.Reset"},
319                              {"@Redfish.ActionInfo", "/redfish/v1/Chassis/" +
320                                                          chassisId +
321                                                          "/ResetActionInfo"}};
322                         asyncResp->res.jsonValue["PCIeDevices"] = {
323                             {"@odata.id",
324                              "/redfish/v1/Systems/system/PCIeDevices"}};
325 
326                         const std::string& connectionName =
327                             connectionNames[0].first;
328 
329                         const std::vector<std::string>& interfaces2 =
330                             connectionNames[0].second;
331                         const std::array<const char*, 2> hasIndicatorLed = {
332                             "xyz.openbmc_project.Inventory.Item.Panel",
333                             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
334 
335                         const std::string assetTagInterface =
336                             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
337                         if (std::find(interfaces2.begin(), interfaces2.end(),
338                                       assetTagInterface) != interfaces2.end())
339                         {
340                             crow::connections::systemBus->async_method_call(
341                                 [asyncResp, chassisId(std::string(chassisId))](
342                                     const boost::system::error_code ec,
343                                     const dbus::utility::DbusVariantType&
344                                         property) {
345                                     if (ec)
346                                     {
347                                         BMCWEB_LOG_DEBUG
348                                             << "DBus response error for AssetTag";
349                                         messages::internalError(asyncResp->res);
350                                         return;
351                                     }
352 
353                                     const std::string* assetTag =
354                                         std::get_if<std::string>(&property);
355                                     if (assetTag == nullptr)
356                                     {
357                                         BMCWEB_LOG_DEBUG
358                                             << "Null value returned for Chassis AssetTag";
359                                         messages::internalError(asyncResp->res);
360                                         return;
361                                     }
362                                     asyncResp->res.jsonValue["AssetTag"] =
363                                         *assetTag;
364                                 },
365                                 connectionName, path,
366                                 "org.freedesktop.DBus.Properties", "Get",
367                                 assetTagInterface, "AssetTag");
368                         }
369 
370                         for (const char* interface : hasIndicatorLed)
371                         {
372                             if (std::find(interfaces2.begin(),
373                                           interfaces2.end(),
374                                           interface) != interfaces2.end())
375                             {
376                                 getIndicatorLedState(asyncResp);
377                                 getLocationIndicatorActive(asyncResp);
378                                 break;
379                             }
380                         }
381 
382                         crow::connections::systemBus->async_method_call(
383                             [asyncResp, chassisId(std::string(chassisId))](
384                                 const boost::system::error_code /*ec2*/,
385                                 const std::vector<
386                                     std::pair<std::string,
387                                               dbus::utility::DbusVariantType>>&
388                                     propertiesList) {
389                                 for (const std::pair<
390                                          std::string,
391                                          dbus::utility::DbusVariantType>&
392                                          property : propertiesList)
393                                 {
394                                     // Store DBus properties that are also
395                                     // Redfish properties with same name and a
396                                     // string value
397                                     const std::string& propertyName =
398                                         property.first;
399                                     if ((propertyName == "PartNumber") ||
400                                         (propertyName == "SerialNumber") ||
401                                         (propertyName == "Manufacturer") ||
402                                         (propertyName == "Model") ||
403                                         (propertyName == "SparePartNumber"))
404                                     {
405                                         const std::string* value =
406                                             std::get_if<std::string>(
407                                                 &property.second);
408                                         if (value == nullptr)
409                                         {
410                                             BMCWEB_LOG_ERROR
411                                                 << "Null value returned for "
412                                                 << propertyName;
413                                             messages::internalError(
414                                                 asyncResp->res);
415                                             return;
416                                         }
417                                         // SparePartNumber is optional on D-Bus
418                                         // so skip if it is empty
419                                         if (propertyName == "SparePartNumber")
420                                         {
421                                             if (*value == "")
422                                             {
423                                                 continue;
424                                             }
425                                         }
426                                         asyncResp->res.jsonValue[propertyName] =
427                                             *value;
428                                     }
429                                 }
430                                 asyncResp->res.jsonValue["Name"] = chassisId;
431                                 asyncResp->res.jsonValue["Id"] = chassisId;
432 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
433                                 asyncResp->res.jsonValue["Thermal"] = {
434                                     {"@odata.id", "/redfish/v1/Chassis/" +
435                                                       chassisId + "/Thermal"}};
436                                 // Power object
437                                 asyncResp->res.jsonValue["Power"] = {
438                                     {"@odata.id", "/redfish/v1/Chassis/" +
439                                                       chassisId + "/Power"}};
440 #endif
441                                 // SensorCollection
442                                 asyncResp->res.jsonValue["Sensors"] = {
443                                     {"@odata.id", "/redfish/v1/Chassis/" +
444                                                       chassisId + "/Sensors"}};
445                                 asyncResp->res.jsonValue["Status"] = {
446                                     {"State", "Enabled"},
447                                 };
448 
449                                 asyncResp->res
450                                     .jsonValue["Links"]["ComputerSystems"] = {
451                                     {{"@odata.id",
452                                       "/redfish/v1/Systems/system"}}};
453                                 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
454                                     {{{"@odata.id",
455                                        "/redfish/v1/Managers/bmc"}}};
456                                 getChassisState(asyncResp);
457                             },
458                             connectionName, path,
459                             "org.freedesktop.DBus.Properties", "GetAll",
460                             "xyz.openbmc_project.Inventory.Decorator.Asset");
461 
462                         for (const auto& interface : interfaces2)
463                         {
464                             if (interface == "xyz.openbmc_project.Common.UUID")
465                             {
466                                 getChassisUUID(asyncResp, connectionName, path);
467                             }
468                             else if (
469                                 interface ==
470                                 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
471                             {
472                                 getChassisLocationCode(asyncResp,
473                                                        connectionName, path);
474                             }
475                         }
476 
477                         return;
478                     }
479 
480                     // Couldn't find an object with that name.  return an error
481                     messages::resourceNotFound(
482                         asyncResp->res, "#Chassis.v1_14_0.Chassis", chassisId);
483                 },
484                 "xyz.openbmc_project.ObjectMapper",
485                 "/xyz/openbmc_project/object_mapper",
486                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
487                 "/xyz/openbmc_project/inventory", 0, interfaces);
488 
489             getPhysicalSecurityData(asyncResp);
490         });
491 
492     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
493         .privileges(redfish::privileges::patchChassis)
494         .methods(
495             boost::beast::http::verb::
496                 patch)([](const crow::Request& req,
497                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
498                           const std::string& param) {
499             std::optional<bool> locationIndicatorActive;
500             std::optional<std::string> indicatorLed;
501 
502             if (param.empty())
503             {
504                 return;
505             }
506 
507             if (!json_util::readJson(
508                     req, asyncResp->res, "LocationIndicatorActive",
509                     locationIndicatorActive, "IndicatorLED", indicatorLed))
510             {
511                 return;
512             }
513 
514             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
515             if (!locationIndicatorActive && !indicatorLed)
516             {
517                 return; // delete this when we support more patch properties
518             }
519             if (indicatorLed)
520             {
521                 asyncResp->res.addHeader(
522                     boost::beast::http::field::warning,
523                     "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
524             }
525 
526             const std::array<const char*, 2> interfaces = {
527                 "xyz.openbmc_project.Inventory.Item.Board",
528                 "xyz.openbmc_project.Inventory.Item.Chassis"};
529 
530             const std::string& chassisId = param;
531 
532             crow::connections::systemBus->async_method_call(
533                 [asyncResp, chassisId, locationIndicatorActive, indicatorLed](
534                     const boost::system::error_code ec,
535                     const crow::openbmc_mapper::GetSubTreeType& subtree) {
536                     if (ec)
537                     {
538                         messages::internalError(asyncResp->res);
539                         return;
540                     }
541 
542                     // Iterate over all retrieved ObjectPaths.
543                     for (const std::pair<
544                              std::string,
545                              std::vector<std::pair<std::string,
546                                                    std::vector<std::string>>>>&
547                              object : subtree)
548                     {
549                         const std::string& path = object.first;
550                         const std::vector<
551                             std::pair<std::string, std::vector<std::string>>>&
552                             connectionNames = object.second;
553 
554                         sdbusplus::message::object_path objPath(path);
555                         if (objPath.filename() != chassisId)
556                         {
557                             continue;
558                         }
559 
560                         if (connectionNames.size() < 1)
561                         {
562                             BMCWEB_LOG_ERROR << "Got 0 Connection names";
563                             continue;
564                         }
565 
566                         const std::vector<std::string>& interfaces3 =
567                             connectionNames[0].second;
568 
569                         const std::array<const char*, 2> hasIndicatorLed = {
570                             "xyz.openbmc_project.Inventory.Item.Panel",
571                             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
572                         bool indicatorChassis = false;
573                         for (const char* interface : hasIndicatorLed)
574                         {
575                             if (std::find(interfaces3.begin(),
576                                           interfaces3.end(),
577                                           interface) != interfaces3.end())
578                             {
579                                 indicatorChassis = true;
580                                 break;
581                             }
582                         }
583                         if (locationIndicatorActive)
584                         {
585                             if (indicatorChassis)
586                             {
587                                 setLocationIndicatorActive(
588                                     asyncResp, *locationIndicatorActive);
589                             }
590                             else
591                             {
592                                 messages::propertyUnknown(
593                                     asyncResp->res, "LocationIndicatorActive");
594                             }
595                         }
596                         if (indicatorLed)
597                         {
598                             if (indicatorChassis)
599                             {
600                                 setIndicatorLedState(asyncResp, *indicatorLed);
601                             }
602                             else
603                             {
604                                 messages::propertyUnknown(asyncResp->res,
605                                                           "IndicatorLED");
606                             }
607                         }
608                         return;
609                     }
610 
611                     messages::resourceNotFound(
612                         asyncResp->res, "#Chassis.v1_14_0.Chassis", chassisId);
613                 },
614                 "xyz.openbmc_project.ObjectMapper",
615                 "/xyz/openbmc_project/object_mapper",
616                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
617                 "/xyz/openbmc_project/inventory", 0, interfaces);
618         });
619 }
620 
621 inline void
622     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
623 {
624     const char* busName = "xyz.openbmc_project.ObjectMapper";
625     const char* path = "/xyz/openbmc_project/object_mapper";
626     const char* interface = "xyz.openbmc_project.ObjectMapper";
627     const char* method = "GetSubTreePaths";
628 
629     const std::array<const char*, 1> interfaces = {
630         "xyz.openbmc_project.State.Chassis"};
631 
632     // Use mapper to get subtree paths.
633     crow::connections::systemBus->async_method_call(
634         [asyncResp](const boost::system::error_code ec,
635                     const std::vector<std::string>& chassisList) {
636             if (ec)
637             {
638                 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
639                 messages::internalError(asyncResp->res);
640                 return;
641             }
642 
643             const char* processName = "xyz.openbmc_project.State.Chassis";
644             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
645             const char* destProperty = "RequestedPowerTransition";
646             const std::string propertyValue =
647                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
648             std::string objectPath =
649                 "/xyz/openbmc_project/state/chassis_system0";
650 
651             /* Look for system reset chassis path */
652             if ((std::find(chassisList.begin(), chassisList.end(),
653                            objectPath)) == chassisList.end())
654             {
655                 /* We prefer to reset the full chassis_system, but if it doesn't
656                  * exist on some platforms, fall back to a host-only power reset
657                  */
658                 objectPath = "/xyz/openbmc_project/state/chassis0";
659             }
660 
661             crow::connections::systemBus->async_method_call(
662                 [asyncResp](const boost::system::error_code ec) {
663                     // Use "Set" method to set the property value.
664                     if (ec)
665                     {
666                         BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: "
667                                          << ec;
668                         messages::internalError(asyncResp->res);
669                         return;
670                     }
671 
672                     messages::success(asyncResp->res);
673                 },
674                 processName, objectPath, "org.freedesktop.DBus.Properties",
675                 "Set", interfaceName, destProperty,
676                 dbus::utility::DbusVariantType{propertyValue});
677         },
678         busName, path, interface, method, "/", 0, interfaces);
679 }
680 
681 /**
682  * ChassisResetAction class supports the POST method for the Reset
683  * action.
684  * Function handles POST method request.
685  * Analyzes POST body before sending Reset request data to D-Bus.
686  */
687 
688 inline void requestRoutesChassisResetAction(App& app)
689 {
690     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
691         .privileges(redfish::privileges::postChassis)
692         .methods(boost::beast::http::verb::post)(
693             [](const crow::Request& req,
694                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
695                const std::string&) {
696                 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
697 
698                 std::string resetType;
699 
700                 if (!json_util::readJson(req, asyncResp->res, "ResetType",
701                                          resetType))
702                 {
703                     return;
704                 }
705 
706                 if (resetType != "PowerCycle")
707                 {
708                     BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
709                                      << resetType;
710                     messages::actionParameterNotSupported(
711                         asyncResp->res, resetType, "ResetType");
712 
713                     return;
714                 }
715                 doChassisPowerCycle(asyncResp);
716             });
717 }
718 
719 /**
720  * ChassisResetActionInfo derived class for delivering Chassis
721  * ResetType AllowableValues using ResetInfo schema.
722  */
723 inline void requestRoutesChassisResetActionInfo(App& app)
724 {
725     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
726         .privileges(redfish::privileges::getActionInfo)
727         .methods(boost::beast::http::verb::get)(
728             [](const crow::Request&,
729                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
730                const std::string& chassisId)
731 
732             {
733                 asyncResp->res.jsonValue = {
734                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
735                     {"@odata.id",
736                      "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo"},
737                     {"Name", "Reset Action Info"},
738                     {"Id", "ResetActionInfo"},
739                     {"Parameters",
740                      {{{"Name", "ResetType"},
741                        {"Required", true},
742                        {"DataType", "String"},
743                        {"AllowableValues", {"PowerCycle"}}}}}};
744             });
745 }
746 
747 } // namespace redfish
748