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