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