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