xref: /openbmc/bmcweb/redfish-core/lib/chassis.hpp (revision 002d39b4)
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->res))
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->res))
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                 const std::string& connectionName = connectionNames[0].first;
288 
289                 const std::vector<std::string>& interfaces2 =
290                     connectionNames[0].second;
291                 const std::array<const char*, 2> hasIndicatorLed = {
292                     "xyz.openbmc_project.Inventory.Item.Panel",
293                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
294 
295                 const std::string assetTagInterface =
296                     "xyz.openbmc_project.Inventory.Decorator.AssetTag";
297                 if (std::find(interfaces2.begin(), interfaces2.end(),
298                               assetTagInterface) != interfaces2.end())
299                 {
300                     sdbusplus::asio::getProperty<std::string>(
301                         *crow::connections::systemBus, connectionName, path,
302                         assetTagInterface, "AssetTag",
303                         [asyncResp, chassisId(std::string(chassisId))](
304                             const boost::system::error_code ec,
305                             const std::string& property) {
306                         if (ec)
307                         {
308                             BMCWEB_LOG_DEBUG
309                                 << "DBus response error for AssetTag";
310                             messages::internalError(asyncResp->res);
311                             return;
312                         }
313                         asyncResp->res.jsonValue["AssetTag"] = property;
314                         });
315                 }
316 
317                 for (const char* interface : hasIndicatorLed)
318                 {
319                     if (std::find(interfaces2.begin(), interfaces2.end(),
320                                   interface) != interfaces2.end())
321                     {
322                         getIndicatorLedState(asyncResp);
323                         getLocationIndicatorActive(asyncResp);
324                         break;
325                     }
326                 }
327 
328                 crow::connections::systemBus->async_method_call(
329                     [asyncResp, chassisId(std::string(chassisId))](
330                         const boost::system::error_code /*ec2*/,
331                         const dbus::utility::DBusPropertiesMap&
332                             propertiesList) {
333                     for (const std::pair<std::string,
334                                          dbus::utility::DbusVariantType>&
335                              property : propertiesList)
336                     {
337                         // Store DBus properties that are also
338                         // Redfish properties with same name and a
339                         // string value
340                         const std::string& propertyName = property.first;
341                         if ((propertyName == "PartNumber") ||
342                             (propertyName == "SerialNumber") ||
343                             (propertyName == "Manufacturer") ||
344                             (propertyName == "Model") ||
345                             (propertyName == "SparePartNumber"))
346                         {
347                             const std::string* value =
348                                 std::get_if<std::string>(&property.second);
349                             if (value == nullptr)
350                             {
351                                 BMCWEB_LOG_ERROR << "Null value returned for "
352                                                  << propertyName;
353                                 messages::internalError(asyncResp->res);
354                                 return;
355                             }
356                             // SparePartNumber is optional on D-Bus
357                             // so skip if it is empty
358                             if (propertyName == "SparePartNumber")
359                             {
360                                 if (value->empty())
361                                 {
362                                     continue;
363                                 }
364                             }
365                             asyncResp->res.jsonValue[propertyName] = *value;
366                         }
367                     }
368                     asyncResp->res.jsonValue["Name"] = chassisId;
369                     asyncResp->res.jsonValue["Id"] = chassisId;
370 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
371                     asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
372                         "/redfish/v1/Chassis/" + chassisId + "/Thermal";
373                     // Power object
374                     asyncResp->res.jsonValue["Power"]["@odata.id"] =
375                         "/redfish/v1/Chassis/" + chassisId + "/Power";
376 #endif
377                     // SensorCollection
378                     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
379                         "/redfish/v1/Chassis/" + chassisId + "/Sensors";
380                     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
381 
382                     nlohmann::json::array_t computerSystems;
383                     nlohmann::json::object_t system;
384                     system["@odata.id"] = "/redfish/v1/Systems/system";
385                     computerSystems.push_back(std::move(system));
386                     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
387                         std::move(computerSystems);
388 
389                     nlohmann::json::array_t managedBy;
390                     nlohmann::json::object_t manager;
391                     manager["@odata.id"] = "/redfish/v1/Managers/bmc";
392                     managedBy.push_back(std::move(manager));
393                     asyncResp->res.jsonValue["Links"]["ManagedBy"] =
394                         std::move(managedBy);
395                     getChassisState(asyncResp);
396                     },
397                     connectionName, path, "org.freedesktop.DBus.Properties",
398                     "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
399 
400                 for (const auto& interface : interfaces2)
401                 {
402                     if (interface == "xyz.openbmc_project.Common.UUID")
403                     {
404                         getChassisUUID(asyncResp, connectionName, path);
405                     }
406                     else if (
407                         interface ==
408                         "xyz.openbmc_project.Inventory.Decorator.LocationCode")
409                     {
410                         getChassisLocationCode(asyncResp, connectionName, path);
411                     }
412                 }
413 
414                 return;
415             }
416 
417             // Couldn't find an object with that name.  return an error
418             messages::resourceNotFound(asyncResp->res,
419                                        "#Chassis.v1_16_0.Chassis", chassisId);
420             },
421             "xyz.openbmc_project.ObjectMapper",
422             "/xyz/openbmc_project/object_mapper",
423             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
424             "/xyz/openbmc_project/inventory", 0, interfaces);
425 
426         getPhysicalSecurityData(asyncResp);
427         });
428 
429     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
430         .privileges(redfish::privileges::patchChassis)
431         .methods(boost::beast::http::verb::patch)(
432             [&app](const crow::Request& req,
433                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
434                    const std::string& param) {
435         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
436         {
437             return;
438         }
439         std::optional<bool> locationIndicatorActive;
440         std::optional<std::string> indicatorLed;
441 
442         if (param.empty())
443         {
444             return;
445         }
446 
447         if (!json_util::readJsonPatch(
448                 req, asyncResp->res, "LocationIndicatorActive",
449                 locationIndicatorActive, "IndicatorLED", indicatorLed))
450         {
451             return;
452         }
453 
454         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
455         if (!locationIndicatorActive && !indicatorLed)
456         {
457             return; // delete this when we support more patch properties
458         }
459         if (indicatorLed)
460         {
461             asyncResp->res.addHeader(
462                 boost::beast::http::field::warning,
463                 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
464         }
465 
466         const std::array<const char*, 2> interfaces = {
467             "xyz.openbmc_project.Inventory.Item.Board",
468             "xyz.openbmc_project.Inventory.Item.Chassis"};
469 
470         const std::string& chassisId = param;
471 
472         crow::connections::systemBus->async_method_call(
473             [asyncResp, chassisId, locationIndicatorActive, indicatorLed](
474                 const boost::system::error_code ec,
475                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
476             if (ec)
477             {
478                 messages::internalError(asyncResp->res);
479                 return;
480             }
481 
482             // Iterate over all retrieved ObjectPaths.
483             for (const std::pair<std::string,
484                                  std::vector<std::pair<
485                                      std::string, std::vector<std::string>>>>&
486                      object : subtree)
487             {
488                 const std::string& path = object.first;
489                 const std::vector<
490                     std::pair<std::string, std::vector<std::string>>>&
491                     connectionNames = object.second;
492 
493                 sdbusplus::message::object_path objPath(path);
494                 if (objPath.filename() != chassisId)
495                 {
496                     continue;
497                 }
498 
499                 if (connectionNames.empty())
500                 {
501                     BMCWEB_LOG_ERROR << "Got 0 Connection names";
502                     continue;
503                 }
504 
505                 const std::vector<std::string>& interfaces3 =
506                     connectionNames[0].second;
507 
508                 const std::array<const char*, 2> hasIndicatorLed = {
509                     "xyz.openbmc_project.Inventory.Item.Panel",
510                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
511                 bool indicatorChassis = false;
512                 for (const char* interface : hasIndicatorLed)
513                 {
514                     if (std::find(interfaces3.begin(), interfaces3.end(),
515                                   interface) != interfaces3.end())
516                     {
517                         indicatorChassis = true;
518                         break;
519                     }
520                 }
521                 if (locationIndicatorActive)
522                 {
523                     if (indicatorChassis)
524                     {
525                         setLocationIndicatorActive(asyncResp,
526                                                    *locationIndicatorActive);
527                     }
528                     else
529                     {
530                         messages::propertyUnknown(asyncResp->res,
531                                                   "LocationIndicatorActive");
532                     }
533                 }
534                 if (indicatorLed)
535                 {
536                     if (indicatorChassis)
537                     {
538                         setIndicatorLedState(asyncResp, *indicatorLed);
539                     }
540                     else
541                     {
542                         messages::propertyUnknown(asyncResp->res,
543                                                   "IndicatorLED");
544                     }
545                 }
546                 return;
547             }
548 
549             messages::resourceNotFound(asyncResp->res,
550                                        "#Chassis.v1_14_0.Chassis", chassisId);
551             },
552             "xyz.openbmc_project.ObjectMapper",
553             "/xyz/openbmc_project/object_mapper",
554             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
555             "/xyz/openbmc_project/inventory", 0, interfaces);
556         });
557 }
558 
559 inline void
560     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
561 {
562     const char* busName = "xyz.openbmc_project.ObjectMapper";
563     const char* path = "/xyz/openbmc_project/object_mapper";
564     const char* interface = "xyz.openbmc_project.ObjectMapper";
565     const char* method = "GetSubTreePaths";
566 
567     const std::array<const char*, 1> interfaces = {
568         "xyz.openbmc_project.State.Chassis"};
569 
570     // Use mapper to get subtree paths.
571     crow::connections::systemBus->async_method_call(
572         [asyncResp](
573             const boost::system::error_code ec,
574             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
575         if (ec)
576         {
577             BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
578             messages::internalError(asyncResp->res);
579             return;
580         }
581 
582         const char* processName = "xyz.openbmc_project.State.Chassis";
583         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
584         const char* destProperty = "RequestedPowerTransition";
585         const std::string propertyValue =
586             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
587         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
588 
589         /* Look for system reset chassis path */
590         if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
591             chassisList.end())
592         {
593             /* We prefer to reset the full chassis_system, but if it doesn't
594              * exist on some platforms, fall back to a host-only power reset
595              */
596             objectPath = "/xyz/openbmc_project/state/chassis0";
597         }
598 
599         crow::connections::systemBus->async_method_call(
600             [asyncResp](const boost::system::error_code ec) {
601             // Use "Set" method to set the property value.
602             if (ec)
603             {
604                 BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec;
605                 messages::internalError(asyncResp->res);
606                 return;
607             }
608 
609             messages::success(asyncResp->res);
610             },
611             processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
612             interfaceName, destProperty,
613             dbus::utility::DbusVariantType{propertyValue});
614         },
615         busName, path, interface, method, "/", 0, interfaces);
616 }
617 
618 /**
619  * ChassisResetAction class supports the POST method for the Reset
620  * action.
621  * Function handles POST method request.
622  * Analyzes POST body before sending Reset request data to D-Bus.
623  */
624 
625 inline void requestRoutesChassisResetAction(App& app)
626 {
627     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
628         .privileges(redfish::privileges::postChassis)
629         .methods(boost::beast::http::verb::post)(
630             [&app](const crow::Request& req,
631                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
632                    const std::string&) {
633         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
634         {
635             return;
636         }
637         BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
638 
639         std::string resetType;
640 
641         if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
642                                        resetType))
643         {
644             return;
645         }
646 
647         if (resetType != "PowerCycle")
648         {
649             BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
650                              << resetType;
651             messages::actionParameterNotSupported(asyncResp->res, resetType,
652                                                   "ResetType");
653 
654             return;
655         }
656         doChassisPowerCycle(asyncResp);
657         });
658 }
659 
660 /**
661  * ChassisResetActionInfo derived class for delivering Chassis
662  * ResetType AllowableValues using ResetInfo schema.
663  */
664 inline void requestRoutesChassisResetActionInfo(App& app)
665 {
666     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
667         .privileges(redfish::privileges::getActionInfo)
668         .methods(boost::beast::http::verb::get)(
669             [&app](const crow::Request& req,
670                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
671                    const std::string& chassisId) {
672         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
673         {
674             return;
675         }
676         asyncResp->res.jsonValue["@odata.type"] =
677             "#ActionInfo.v1_1_2.ActionInfo";
678         asyncResp->res.jsonValue["@odata.id"] =
679             "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
680         asyncResp->res.jsonValue["Name"] = "Reset Action Info";
681 
682         asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
683         nlohmann::json::object_t parameters;
684         parameters["Name"] = "ResetType";
685         parameters["Required"] = true;
686         parameters["DataType"] = "String";
687         nlohmann::json::array_t allowed;
688         allowed.push_back("PowerCycle");
689         parameters["AllowableValues"] = std::move(allowed);
690         asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
691         });
692 }
693 
694 } // namespace redfish
695