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