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