xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 997093eb732dc889bd76f7aaa65e16a2aa4d7224)
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 "
193                                     "Location";
194                 messages::internalError(asyncResp->res);
195                 return;
196             }
197 
198             const std::string* value = std::get_if<std::string>(&property);
199             if (value == nullptr)
200             {
201                 BMCWEB_LOG_DEBUG << "Null value returned "
202                                     "for locaton code";
203                 messages::internalError(asyncResp->res);
204                 return;
205             }
206             asyncResp->res
207                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = *value;
208         },
209         connectionName, path, "org.freedesktop.DBus.Properties", "Get",
210         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
211 }
212 
213 inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
214                            const std::string& connectionName,
215                            const std::string& path)
216 {
217     crow::connections::systemBus->async_method_call(
218         [asyncResp](const boost::system::error_code ec,
219                     const std::variant<std::string>& chassisUUID) {
220             if (ec)
221             {
222                 BMCWEB_LOG_DEBUG << "DBUS response error for "
223                                     "UUID";
224                 messages::internalError(asyncResp->res);
225                 return;
226             }
227             const std::string* value = std::get_if<std::string>(&chassisUUID);
228             if (value == nullptr)
229             {
230                 BMCWEB_LOG_DEBUG << "Null value returned "
231                                     "for UUID";
232                 messages::internalError(asyncResp->res);
233                 return;
234             }
235             asyncResp->res.jsonValue["UUID"] = *value;
236         },
237         connectionName, path, "org.freedesktop.DBus.Properties", "Get",
238         "xyz.openbmc_project.Common.UUID", "UUID");
239 }
240 
241 /**
242  * Chassis override class for delivering Chassis Schema
243  * Functions triggers appropriate requests on DBus
244  */
245 inline void requestRoutesChassis(App& app)
246 {
247     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
248         .privileges(redfish::privileges::getChassis)
249         .methods(
250             boost::beast::http::verb::get)([](const crow::Request&,
251                                               const std::shared_ptr<
252                                                   bmcweb::AsyncResp>& asyncResp,
253                                               const std::string& chassisId) {
254             const std::array<const char*, 2> interfaces = {
255                 "xyz.openbmc_project.Inventory.Item.Board",
256                 "xyz.openbmc_project.Inventory.Item.Chassis"};
257 
258             crow::connections::systemBus->async_method_call(
259                 [asyncResp, chassisId(std::string(chassisId))](
260                     const boost::system::error_code ec,
261                     const crow::openbmc_mapper::GetSubTreeType& subtree) {
262                     if (ec)
263                     {
264                         messages::internalError(asyncResp->res);
265                         return;
266                     }
267                     // Iterate over all retrieved ObjectPaths.
268                     for (const std::pair<
269                              std::string,
270                              std::vector<std::pair<std::string,
271                                                    std::vector<std::string>>>>&
272                              object : subtree)
273                     {
274                         const std::string& path = object.first;
275                         const std::vector<
276                             std::pair<std::string, std::vector<std::string>>>&
277                             connectionNames = object.second;
278 
279                         sdbusplus::message::object_path objPath(path);
280                         if (objPath.filename() != chassisId)
281                         {
282                             continue;
283                         }
284 
285                         auto health =
286                             std::make_shared<HealthPopulate>(asyncResp);
287 
288                         crow::connections::systemBus->async_method_call(
289                             [health](
290                                 const boost::system::error_code ec2,
291                                 std::variant<std::vector<std::string>>& resp) {
292                                 if (ec2)
293                                 {
294                                     return; // no sensors = no failures
295                                 }
296                                 std::vector<std::string>* data =
297                                     std::get_if<std::vector<std::string>>(
298                                         &resp);
299                                 if (data == nullptr)
300                                 {
301                                     return;
302                                 }
303                                 health->inventory = std::move(*data);
304                             },
305                             "xyz.openbmc_project.ObjectMapper",
306                             path + "/all_sensors",
307                             "org.freedesktop.DBus.Properties", "Get",
308                             "xyz.openbmc_project.Association", "endpoints");
309 
310                         health->populate();
311 
312                         if (connectionNames.size() < 1)
313                         {
314                             BMCWEB_LOG_ERROR << "Got 0 Connection names";
315                             continue;
316                         }
317 
318                         asyncResp->res.jsonValue["@odata.type"] =
319                             "#Chassis.v1_14_0.Chassis";
320                         asyncResp->res.jsonValue["@odata.id"] =
321                             "/redfish/v1/Chassis/" + chassisId;
322                         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
323                         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
324                         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] =
325                             {{"target", "/redfish/v1/Chassis/" + chassisId +
326                                             "/Actions/Chassis.Reset"},
327                              {"@Redfish.ActionInfo", "/redfish/v1/Chassis/" +
328                                                          chassisId +
329                                                          "/ResetActionInfo"}};
330                         asyncResp->res.jsonValue["PCIeDevices"] = {
331                             {"@odata.id",
332                              "/redfish/v1/Systems/system/PCIeDevices"}};
333 
334                         const std::string& connectionName =
335                             connectionNames[0].first;
336 
337                         const std::vector<std::string>& interfaces2 =
338                             connectionNames[0].second;
339                         const std::array<const char*, 2> hasIndicatorLed = {
340                             "xyz.openbmc_project.Inventory.Item.Panel",
341                             "xyz.openbmc_project.Inventory.Item.Board."
342                             "Motherboard"};
343 
344                         const std::string assetTagInterface =
345                             "xyz.openbmc_project.Inventory.Decorator."
346                             "AssetTag";
347                         if (std::find(interfaces2.begin(), interfaces2.end(),
348                                       assetTagInterface) != interfaces2.end())
349                         {
350                             crow::connections::systemBus->async_method_call(
351                                 [asyncResp, chassisId(std::string(chassisId))](
352                                     const boost::system::error_code ec,
353                                     const std::variant<std::string>& property) {
354                                     if (ec)
355                                     {
356                                         BMCWEB_LOG_DEBUG
357                                             << "DBus response error for "
358                                                "AssetTag";
359                                         messages::internalError(asyncResp->res);
360                                         return;
361                                     }
362 
363                                     const std::string* assetTag =
364                                         std::get_if<std::string>(&property);
365                                     if (assetTag == nullptr)
366                                     {
367                                         BMCWEB_LOG_DEBUG
368                                             << "Null value returned "
369                                                "for Chassis AssetTag";
370                                         messages::internalError(asyncResp->res);
371                                         return;
372                                     }
373                                     asyncResp->res.jsonValue["AssetTag"] =
374                                         *assetTag;
375                                 },
376                                 connectionName, path,
377                                 "org.freedesktop.DBus.Properties", "Get",
378                                 assetTagInterface, "AssetTag");
379                         }
380 
381                         for (const char* interface : hasIndicatorLed)
382                         {
383                             if (std::find(interfaces2.begin(),
384                                           interfaces2.end(),
385                                           interface) != interfaces2.end())
386                             {
387                                 getIndicatorLedState(asyncResp);
388                                 getLocationIndicatorActive(asyncResp);
389                                 break;
390                             }
391                         }
392 
393                         crow::connections::systemBus->async_method_call(
394                             [asyncResp, chassisId(std::string(chassisId))](
395                                 const boost::system::error_code /*ec2*/,
396                                 const std::vector<
397                                     std::pair<std::string, VariantType>>&
398                                     propertiesList) {
399                                 for (const std::pair<std::string, VariantType>&
400                                          property : propertiesList)
401                                 {
402                                     // Store DBus properties that are also
403                                     // Redfish properties with same name and a
404                                     // string value
405                                     const std::string& propertyName =
406                                         property.first;
407                                     if ((propertyName == "PartNumber") ||
408                                         (propertyName == "SerialNumber") ||
409                                         (propertyName == "Manufacturer") ||
410                                         (propertyName == "Model"))
411                                     {
412                                         const std::string* value =
413                                             std::get_if<std::string>(
414                                                 &property.second);
415                                         if (value != nullptr)
416                                         {
417                                             asyncResp->res
418                                                 .jsonValue[propertyName] =
419                                                 *value;
420                                         }
421                                     }
422                                 }
423                                 asyncResp->res.jsonValue["Name"] = chassisId;
424                                 asyncResp->res.jsonValue["Id"] = chassisId;
425 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
426                                 asyncResp->res.jsonValue["Thermal"] = {
427                                     {"@odata.id", "/redfish/v1/Chassis/" +
428                                                       chassisId + "/Thermal"}};
429                                 // Power object
430                                 asyncResp->res.jsonValue["Power"] = {
431                                     {"@odata.id", "/redfish/v1/Chassis/" +
432                                                       chassisId + "/Power"}};
433 #endif
434                                 // SensorCollection
435                                 asyncResp->res.jsonValue["Sensors"] = {
436                                     {"@odata.id", "/redfish/v1/Chassis/" +
437                                                       chassisId + "/Sensors"}};
438                                 asyncResp->res.jsonValue["Status"] = {
439                                     {"State", "Enabled"},
440                                 };
441 
442                                 asyncResp->res
443                                     .jsonValue["Links"]["ComputerSystems"] = {
444                                     {{"@odata.id",
445                                       "/redfish/v1/Systems/system"}}};
446                                 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
447                                     {{{"@odata.id",
448                                        "/redfish/v1/Managers/bmc"}}};
449                                 getChassisState(asyncResp);
450                             },
451                             connectionName, path,
452                             "org.freedesktop.DBus.Properties", "GetAll",
453                             "xyz.openbmc_project.Inventory.Decorator.Asset");
454 
455                         for (const auto& interface : interfaces2)
456                         {
457                             if (interface == "xyz.openbmc_project.Common.UUID")
458                             {
459                                 getChassisUUID(asyncResp, connectionName, path);
460                             }
461                             else if (interface ==
462                                      "xyz.openbmc_project.Inventory."
463                                      "Decorator.LocationCode")
464                             {
465                                 getChassisLocationCode(asyncResp,
466                                                        connectionName, path);
467                             }
468                         }
469 
470                         return;
471                     }
472 
473                     // Couldn't find an object with that name.  return an error
474                     messages::resourceNotFound(
475                         asyncResp->res, "#Chassis.v1_14_0.Chassis", chassisId);
476                 },
477                 "xyz.openbmc_project.ObjectMapper",
478                 "/xyz/openbmc_project/object_mapper",
479                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
480                 "/xyz/openbmc_project/inventory", 0, interfaces);
481 
482             getPhysicalSecurityData(asyncResp);
483         });
484 
485     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
486         .privileges(redfish::privileges::patchChassis)
487         .methods(
488             boost::beast::http::verb::
489                 patch)([](const crow::Request& req,
490                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
491                           const std::string& param) {
492             std::optional<bool> locationIndicatorActive;
493             std::optional<std::string> indicatorLed;
494 
495             if (param.empty())
496             {
497                 return;
498             }
499 
500             if (!json_util::readJson(
501                     req, asyncResp->res, "LocationIndicatorActive",
502                     locationIndicatorActive, "IndicatorLED", indicatorLed))
503             {
504                 return;
505             }
506 
507             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
508             if (!locationIndicatorActive && !indicatorLed)
509             {
510                 return; // delete this when we support more patch properties
511             }
512             if (indicatorLed)
513             {
514                 asyncResp->res.addHeader(
515                     boost::beast::http::field::warning,
516                     "299 - \"IndicatorLED is deprecated. Use "
517                     "LocationIndicatorActive instead.\"");
518             }
519 
520             const std::array<const char*, 2> interfaces = {
521                 "xyz.openbmc_project.Inventory.Item.Board",
522                 "xyz.openbmc_project.Inventory.Item.Chassis"};
523 
524             const std::string& chassisId = param;
525 
526             crow::connections::systemBus->async_method_call(
527                 [asyncResp, chassisId, locationIndicatorActive, indicatorLed](
528                     const boost::system::error_code ec,
529                     const crow::openbmc_mapper::GetSubTreeType& subtree) {
530                     if (ec)
531                     {
532                         messages::internalError(asyncResp->res);
533                         return;
534                     }
535 
536                     // Iterate over all retrieved ObjectPaths.
537                     for (const std::pair<
538                              std::string,
539                              std::vector<std::pair<std::string,
540                                                    std::vector<std::string>>>>&
541                              object : subtree)
542                     {
543                         const std::string& path = object.first;
544                         const std::vector<
545                             std::pair<std::string, std::vector<std::string>>>&
546                             connectionNames = object.second;
547 
548                         sdbusplus::message::object_path objPath(path);
549                         if (objPath.filename() != chassisId)
550                         {
551                             continue;
552                         }
553 
554                         if (connectionNames.size() < 1)
555                         {
556                             BMCWEB_LOG_ERROR << "Got 0 Connection names";
557                             continue;
558                         }
559 
560                         const std::vector<std::string>& interfaces3 =
561                             connectionNames[0].second;
562 
563                         const std::array<const char*, 2> hasIndicatorLed = {
564                             "xyz.openbmc_project.Inventory.Item.Panel",
565                             "xyz.openbmc_project.Inventory.Item.Board."
566                             "Motherboard"};
567                         bool indicatorChassis = false;
568                         for (const char* interface : hasIndicatorLed)
569                         {
570                             if (std::find(interfaces3.begin(),
571                                           interfaces3.end(),
572                                           interface) != interfaces3.end())
573                             {
574                                 indicatorChassis = true;
575                                 break;
576                             }
577                         }
578                         if (locationIndicatorActive)
579                         {
580                             if (indicatorChassis)
581                             {
582                                 setLocationIndicatorActive(
583                                     asyncResp, *locationIndicatorActive);
584                             }
585                             else
586                             {
587                                 messages::propertyUnknown(
588                                     asyncResp->res, "LocationIndicatorActive");
589                             }
590                         }
591                         if (indicatorLed)
592                         {
593                             if (indicatorChassis)
594                             {
595                                 setIndicatorLedState(asyncResp, *indicatorLed);
596                             }
597                             else
598                             {
599                                 messages::propertyUnknown(asyncResp->res,
600                                                           "IndicatorLED");
601                             }
602                         }
603                         return;
604                     }
605 
606                     messages::resourceNotFound(
607                         asyncResp->res, "#Chassis.v1_14_0.Chassis", chassisId);
608                 },
609                 "xyz.openbmc_project.ObjectMapper",
610                 "/xyz/openbmc_project/object_mapper",
611                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
612                 "/xyz/openbmc_project/inventory", 0, interfaces);
613         });
614 }
615 
616 inline void
617     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
618 {
619     const char* busName = "xyz.openbmc_project.ObjectMapper";
620     const char* path = "/xyz/openbmc_project/object_mapper";
621     const char* interface = "xyz.openbmc_project.ObjectMapper";
622     const char* method = "GetSubTreePaths";
623 
624     const std::array<const char*, 1> interfaces = {
625         "xyz.openbmc_project.State.Chassis"};
626 
627     // Use mapper to get subtree paths.
628     crow::connections::systemBus->async_method_call(
629         [asyncResp](const boost::system::error_code ec,
630                     const std::vector<std::string>& chassisList) {
631             if (ec)
632             {
633                 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
634                 messages::internalError(asyncResp->res);
635                 return;
636             }
637 
638             const char* processName = "xyz.openbmc_project.State.Chassis";
639             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
640             const char* destProperty = "RequestedPowerTransition";
641             const std::string propertyValue =
642                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
643             std::string objectPath =
644                 "/xyz/openbmc_project/state/chassis_system0";
645 
646             /* Look for system reset chassis path */
647             if ((std::find(chassisList.begin(), chassisList.end(),
648                            objectPath)) == chassisList.end())
649             {
650                 /* We prefer to reset the full chassis_system, but if it doesn't
651                  * exist on some platforms, fall back to a host-only power reset
652                  */
653                 objectPath = "/xyz/openbmc_project/state/chassis0";
654             }
655 
656             crow::connections::systemBus->async_method_call(
657                 [asyncResp](const boost::system::error_code ec) {
658                     // Use "Set" method to set the property value.
659                     if (ec)
660                     {
661                         BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: "
662                                          << ec;
663                         messages::internalError(asyncResp->res);
664                         return;
665                     }
666 
667                     messages::success(asyncResp->res);
668                 },
669                 processName, objectPath, "org.freedesktop.DBus.Properties",
670                 "Set", interfaceName, destProperty,
671                 std::variant<std::string>{propertyValue});
672         },
673         busName, path, interface, method, "/", 0, interfaces);
674 }
675 
676 /**
677  * ChassisResetAction class supports the POST method for the Reset
678  * action.
679  * Function handles POST method request.
680  * Analyzes POST body before sending Reset request data to D-Bus.
681  */
682 
683 inline void requestRoutesChassisResetAction(App& app)
684 {
685     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
686         .privileges(redfish::privileges::postChassis)
687         .methods(boost::beast::http::verb::post)(
688             [](const crow::Request& req,
689                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
690                const std::string&) {
691                 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
692 
693                 std::string resetType;
694 
695                 if (!json_util::readJson(req, asyncResp->res, "ResetType",
696                                          resetType))
697                 {
698                     return;
699                 }
700 
701                 if (resetType != "PowerCycle")
702                 {
703                     BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
704                                      << resetType;
705                     messages::actionParameterNotSupported(
706                         asyncResp->res, resetType, "ResetType");
707 
708                     return;
709                 }
710                 doChassisPowerCycle(asyncResp);
711             });
712 }
713 
714 /**
715  * ChassisResetActionInfo derived class for delivering Chassis
716  * ResetType AllowableValues using ResetInfo schema.
717  */
718 inline void requestRoutesChassisResetActionInfo(App& app)
719 {
720     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
721         .privileges(redfish::privileges::getActionInfo)
722         .methods(boost::beast::http::verb::get)(
723             [](const crow::Request&,
724                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
725                const std::string& chassisId)
726 
727             {
728                 asyncResp->res.jsonValue = {
729                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
730                     {"@odata.id",
731                      "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo"},
732                     {"Name", "Reset Action Info"},
733                     {"Id", "ResetActionInfo"},
734                     {"Parameters",
735                      {{{"Name", "ResetType"},
736                        {"Required", true},
737                        {"DataType", "String"},
738                        {"AllowableValues", {"PowerCycle"}}}}}};
739             });
740 }
741 
742 } // namespace redfish
743