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