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