xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 683f7276)
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 "boost/container/flat_map.hpp"
19 #include "node.hpp"
20 
21 #include <utils/json_utils.hpp>
22 
23 namespace redfish
24 {
25 
26 /**
27  * @brief Retrieves computer system properties over dbus
28  *
29  * @param[in] aResp Shared pointer for completing asynchronous calls
30  * @param[in] name  Computer system name from request
31  *
32  * @return None.
33  */
34 void getComputerSystem(std::shared_ptr<AsyncResp> aResp,
35                        const std::string &name)
36 {
37     BMCWEB_LOG_DEBUG << "Get available system components.";
38     crow::connections::systemBus->async_method_call(
39         [name, aResp{std::move(aResp)}](
40             const boost::system::error_code ec,
41             const std::vector<std::pair<
42                 std::string,
43                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
44                 &subtree) {
45             if (ec)
46             {
47                 BMCWEB_LOG_DEBUG << "DBUS response error";
48                 aResp->res.result(
49                     boost::beast::http::status::internal_server_error);
50                 return;
51             }
52             bool foundName = false;
53             // Iterate over all retrieved ObjectPaths.
54             for (const std::pair<std::string,
55                                  std::vector<std::pair<
56                                      std::string, std::vector<std::string>>>>
57                      &object : subtree)
58             {
59                 const std::string &path = object.first;
60                 BMCWEB_LOG_DEBUG << "Got path: " << path;
61                 const std::vector<
62                     std::pair<std::string, std::vector<std::string>>>
63                     &connectionNames = object.second;
64                 if (connectionNames.size() < 1)
65                 {
66                     continue;
67                 }
68                 // Check if computer system exist
69                 if (boost::ends_with(path, name))
70                 {
71                     foundName = true;
72                     BMCWEB_LOG_DEBUG << "Found name: " << name;
73                     const std::string connectionName = connectionNames[0].first;
74                     crow::connections::systemBus->async_method_call(
75                         [aResp, name(std::string(name))](
76                             const boost::system::error_code ec,
77                             const std::vector<std::pair<
78                                 std::string, VariantType>> &propertiesList) {
79                             if (ec)
80                             {
81                                 BMCWEB_LOG_ERROR << "DBUS response error: "
82                                                  << ec;
83                                 aResp->res.result(boost::beast::http::status::
84                                                       internal_server_error);
85                                 return;
86                             }
87                             BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
88                                              << "properties for system";
89                             for (const std::pair<std::string, VariantType>
90                                      &property : propertiesList)
91                             {
92                                 const std::string *value =
93                                     mapbox::getPtr<const std::string>(
94                                         property.second);
95                                 if (value != nullptr)
96                                 {
97                                     aResp->res.jsonValue[property.first] =
98                                         *value;
99                                 }
100                             }
101                             aResp->res.jsonValue["Name"] = name;
102                             aResp->res.jsonValue["Id"] =
103                                 aResp->res.jsonValue["SerialNumber"];
104                         },
105                         connectionName, path, "org.freedesktop.DBus.Properties",
106                         "GetAll",
107                         "xyz.openbmc_project.Inventory.Decorator.Asset");
108                 }
109                 else
110                 {
111                     // This is not system, so check if it's cpu, dimm, UUID or
112                     // BiosVer
113                     for (auto const &s : connectionNames)
114                     {
115                         for (auto const &i : s.second)
116                         {
117                             if (boost::ends_with(i, "Dimm"))
118                             {
119                                 BMCWEB_LOG_DEBUG
120                                     << "Found Dimm, now get it properties.";
121                                 crow::connections::systemBus->async_method_call(
122                                     [aResp](
123                                         const boost::system::error_code ec,
124                                         const std::vector<
125                                             std::pair<std::string, VariantType>>
126                                             &properties) {
127                                         if (ec)
128                                         {
129                                             BMCWEB_LOG_ERROR
130                                                 << "DBUS response error " << ec;
131                                             aResp->res.result(
132                                                 boost::beast::http::status::
133                                                     internal_server_error);
134                                             return;
135                                         }
136                                         BMCWEB_LOG_DEBUG << "Got "
137                                                          << properties.size()
138                                                          << "Dimm properties.";
139                                         for (const auto &p : properties)
140                                         {
141                                             if (p.first == "MemorySize")
142                                             {
143                                                 const std::string *value =
144                                                     mapbox::getPtr<
145                                                         const std::string>(
146                                                         p.second);
147                                                 if ((value != nullptr) &&
148                                                     (*value != "NULL"))
149                                                 {
150                                                     // Remove units char
151                                                     int32_t unitCoeff;
152                                                     if (boost::ends_with(*value,
153                                                                          "MB"))
154                                                     {
155                                                         unitCoeff = 1000;
156                                                     }
157                                                     else if (boost::ends_with(
158                                                                  *value, "KB"))
159                                                     {
160                                                         unitCoeff = 1000000;
161                                                     }
162                                                     else
163                                                     {
164                                                         BMCWEB_LOG_ERROR
165                                                             << "Unsupported "
166                                                                "memory units";
167                                                         aResp->res.result(
168                                                             boost::beast::http::
169                                                                 status::
170                                                                     internal_server_error);
171                                                         return;
172                                                     }
173 
174                                                     auto memSize =
175                                                         boost::lexical_cast<
176                                                             int>(value->substr(
177                                                             0, value->length() -
178                                                                    2));
179                                                     aResp->res.jsonValue
180                                                         ["TotalSystemMemoryGi"
181                                                          "B"] +=
182                                                         memSize * unitCoeff;
183                                                     aResp->res.jsonValue
184                                                         ["MemorySummary"]
185                                                         ["Status"]["State"] =
186                                                         "Enabled";
187                                                 }
188                                             }
189                                         }
190                                     },
191                                     s.first, path,
192                                     "org.freedesktop.DBus.Properties", "GetAll",
193                                     "xyz.openbmc_project.Inventory.Item.Dimm");
194                             }
195                             else if (boost::ends_with(i, "Cpu"))
196                             {
197                                 BMCWEB_LOG_DEBUG
198                                     << "Found Cpu, now get it properties.";
199                                 crow::connections::systemBus->async_method_call(
200                                     [aResp](
201                                         const boost::system::error_code ec,
202                                         const std::vector<
203                                             std::pair<std::string, VariantType>>
204                                             &properties) {
205                                         if (ec)
206                                         {
207                                             BMCWEB_LOG_ERROR
208                                                 << "DBUS response error " << ec;
209                                             aResp->res.result(
210                                                 boost::beast::http::status::
211                                                     internal_server_error);
212                                             return;
213                                         }
214                                         BMCWEB_LOG_DEBUG << "Got "
215                                                          << properties.size()
216                                                          << "Cpu properties.";
217                                         for (const auto &p : properties)
218                                         {
219                                             if (p.first == "ProcessorFamily")
220                                             {
221                                                 const std::string *value =
222                                                     mapbox::getPtr<
223                                                         const std::string>(
224                                                         p.second);
225                                                 if (value != nullptr)
226                                                 {
227                                                     aResp->res.jsonValue
228                                                         ["ProcessorSummary"]
229                                                         ["Count"] =
230                                                         aResp->res
231                                                             .jsonValue
232                                                                 ["ProcessorSumm"
233                                                                  "ary"]["Count"]
234                                                             .get<int>() +
235                                                         1;
236                                                     aResp->res.jsonValue
237                                                         ["ProcessorSummary"]
238                                                         ["Status"]["State"] =
239                                                         "Enabled";
240                                                     aResp->res.jsonValue
241                                                         ["ProcessorSummary"]
242                                                         ["Model"] = *value;
243                                                 }
244                                             }
245                                         }
246                                     },
247                                     s.first, path,
248                                     "org.freedesktop.DBus.Properties", "GetAll",
249                                     "xyz.openbmc_project.Inventory.Item.Cpu");
250                             }
251                             else if (boost::ends_with(i, "UUID"))
252                             {
253                                 BMCWEB_LOG_DEBUG
254                                     << "Found UUID, now get it properties.";
255                                 crow::connections::systemBus->async_method_call(
256                                     [aResp](
257                                         const boost::system::error_code ec,
258                                         const std::vector<
259                                             std::pair<std::string, VariantType>>
260                                             &properties) {
261                                         if (ec)
262                                         {
263                                             BMCWEB_LOG_DEBUG
264                                                 << "DBUS response error " << ec;
265                                             aResp->res.result(
266                                                 boost::beast::http::status::
267                                                     internal_server_error);
268                                             return;
269                                         }
270                                         BMCWEB_LOG_DEBUG << "Got "
271                                                          << properties.size()
272                                                          << "UUID properties.";
273                                         for (const std::pair<std::string,
274                                                              VariantType> &p :
275                                              properties)
276                                         {
277                                             if (p.first == "BIOSVer")
278                                             {
279                                                 const std::string *value =
280                                                     mapbox::getPtr<
281                                                         const std::string>(
282                                                         p.second);
283                                                 if (value != nullptr)
284                                                 {
285                                                     aResp->res.jsonValue
286                                                         ["BiosVersion"] =
287                                                         *value;
288                                                 }
289                                             }
290                                             if (p.first == "UUID")
291                                             {
292                                                 const std::string *value =
293                                                     mapbox::getPtr<
294                                                         const std::string>(
295                                                         p.second);
296                                                 BMCWEB_LOG_DEBUG
297                                                     << "UUID = " << *value
298                                                     << " length "
299                                                     << value->length();
300                                                 if (value != nullptr)
301                                                 {
302                                                     // Workaround for to short
303                                                     // return str in smbios demo
304                                                     // app, 32 bytes are
305                                                     // described by spec
306                                                     if (value->length() > 0 &&
307                                                         value->length() < 32)
308                                                     {
309                                                         std::string
310                                                             correctedValue =
311                                                                 *value;
312                                                         correctedValue.append(
313                                                             32 -
314                                                                 value->length(),
315                                                             '0');
316                                                         value = &correctedValue;
317                                                     }
318                                                     else if (value->length() ==
319                                                              32)
320                                                     {
321                                                         aResp->res
322                                                             .jsonValue["UUID"] =
323                                                             value->substr(0,
324                                                                           8) +
325                                                             "-" +
326                                                             value->substr(8,
327                                                                           4) +
328                                                             "-" +
329                                                             value->substr(12,
330                                                                           4) +
331                                                             "-" +
332                                                             value->substr(16,
333                                                                           4) +
334                                                             "-" +
335                                                             value->substr(20,
336                                                                           12);
337                                                     }
338                                                 }
339                                             }
340                                         }
341                                     },
342                                     s.first, path,
343                                     "org.freedesktop.DBus.Properties", "GetAll",
344                                     "xyz.openbmc_project.Common.UUID");
345                             }
346                         }
347                     }
348                 }
349             }
350             if (foundName == false)
351             {
352                 aResp->res.result(
353                     boost::beast::http::status::internal_server_error);
354             }
355         },
356         "xyz.openbmc_project.ObjectMapper",
357         "/xyz/openbmc_project/object_mapper",
358         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
359         "/xyz/openbmc_project/inventory", int32_t(0),
360         std::array<const char *, 5>{
361             "xyz.openbmc_project.Inventory.Decorator.Asset",
362             "xyz.openbmc_project.Inventory.Item.Cpu",
363             "xyz.openbmc_project.Inventory.Item.Dimm",
364             "xyz.openbmc_project.Inventory.Item.System",
365             "xyz.openbmc_project.Common.UUID",
366         });
367 }
368 
369 /**
370  * @brief Retrieves identify led group properties over dbus
371  *
372  * @param[in] aResp     Shared pointer for completing asynchronous calls.
373  * @param[in] callback  Callback for process retrieved data.
374  *
375  * @return None.
376  */
377 template <typename CallbackFunc>
378 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp,
379                          CallbackFunc &&callback)
380 {
381     BMCWEB_LOG_DEBUG << "Get led groups";
382     crow::connections::systemBus->async_method_call(
383         [aResp{std::move(aResp)},
384          callback{std::move(callback)}](const boost::system::error_code &ec,
385                                         const ManagedObjectsType &resp) {
386             if (ec)
387             {
388                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
389                 aResp->res.result(
390                     boost::beast::http::status::internal_server_error);
391                 return;
392             }
393             BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects.";
394             for (const auto &objPath : resp)
395             {
396                 const std::string &path = objPath.first;
397                 if (path.rfind("enclosure_identify") != std::string::npos)
398                 {
399                     for (const auto &interface : objPath.second)
400                     {
401                         if (interface.first == "xyz.openbmc_project.Led.Group")
402                         {
403                             for (const auto &property : interface.second)
404                             {
405                                 if (property.first == "Asserted")
406                                 {
407                                     const bool *asserted =
408                                         mapbox::getPtr<const bool>(
409                                             property.second);
410                                     if (nullptr != asserted)
411                                     {
412                                         callback(*asserted, aResp);
413                                     }
414                                     else
415                                     {
416                                         callback(false, aResp);
417                                     }
418                                 }
419                             }
420                         }
421                     }
422                 }
423             }
424         },
425         "xyz.openbmc_project.LED.GroupManager",
426         "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager",
427         "GetManagedObjects");
428 }
429 
430 template <typename CallbackFunc>
431 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback)
432 {
433     BMCWEB_LOG_DEBUG << "Get identify led properties";
434     crow::connections::systemBus->async_method_call(
435         [aResp,
436          callback{std::move(callback)}](const boost::system::error_code ec,
437                                         const PropertiesType &properties) {
438             if (ec)
439             {
440                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
441                 aResp->res.result(
442                     boost::beast::http::status::internal_server_error);
443                 return;
444             }
445             BMCWEB_LOG_DEBUG << "Got " << properties.size()
446                              << "led properties.";
447             std::string output;
448             for (const auto &property : properties)
449             {
450                 if (property.first == "State")
451                 {
452                     const std::string *s =
453                         mapbox::getPtr<std::string>(property.second);
454                     if (nullptr != s)
455                     {
456                         BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
457                         const auto pos = s->rfind('.');
458                         if (pos != std::string::npos)
459                         {
460                             auto led = s->substr(pos + 1);
461                             for (const std::pair<const char *, const char *>
462                                      &p :
463                                  std::array<
464                                      std::pair<const char *, const char *>, 3>{
465                                      {{"On", "Lit"},
466                                       {"Blink", "Blinking"},
467                                       {"Off", "Off"}}})
468                             {
469                                 if (led == p.first)
470                                 {
471                                     output = p.second;
472                                 }
473                             }
474                         }
475                     }
476                 }
477             }
478             callback(output, aResp);
479         },
480         "xyz.openbmc_project.LED.Controller.identify",
481         "/xyz/openbmc_project/led/physical/identify",
482         "org.freedesktop.DBus.Properties", "GetAll",
483         "xyz.openbmc_project.Led.Physical");
484 }
485 
486 /**
487  * @brief Retrieves host state properties over dbus
488  *
489  * @param[in] aResp     Shared pointer for completing asynchronous calls.
490  *
491  * @return None.
492  */
493 void getHostState(std::shared_ptr<AsyncResp> aResp)
494 {
495     BMCWEB_LOG_DEBUG << "Get host information.";
496     crow::connections::systemBus->async_method_call(
497         [aResp{std::move(aResp)}](
498             const boost::system::error_code ec,
499             const sdbusplus::message::variant<std::string> &hostState) {
500             if (ec)
501             {
502                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
503                 aResp->res.result(
504                     boost::beast::http::status::internal_server_error);
505                 return;
506             }
507 
508             const std::string *s = mapbox::getPtr<const std::string>(hostState);
509             BMCWEB_LOG_DEBUG << "Host state: " << *s;
510             if (s != nullptr)
511             {
512                 // Verify Host State
513                 if (*s == "xyz.openbmc_project.State.Host.Running")
514                 {
515                     aResp->res.jsonValue["PowerState"] = "On";
516                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
517                 }
518                 else
519                 {
520                     aResp->res.jsonValue["PowerState"] = "Off";
521                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
522                 }
523             }
524         },
525         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
526         "org.freedesktop.DBus.Properties", "Get",
527         "xyz.openbmc_project.State.Host", "CurrentHostState");
528 }
529 
530 /**
531  * SystemsCollection derived class for delivering ComputerSystems Collection
532  * Schema
533  */
534 class SystemsCollection : public Node
535 {
536   public:
537     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
538     {
539         Node::json["@odata.type"] =
540             "#ComputerSystemCollection.ComputerSystemCollection";
541         Node::json["@odata.id"] = "/redfish/v1/Systems";
542         Node::json["@odata.context"] =
543             "/redfish/v1/"
544             "$metadata#ComputerSystemCollection.ComputerSystemCollection";
545         Node::json["Name"] = "Computer System Collection";
546 
547         entityPrivileges = {
548             {boost::beast::http::verb::get, {{"Login"}}},
549             {boost::beast::http::verb::head, {{"Login"}}},
550             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
551             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
552             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
553             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
554     }
555 
556   private:
557     void doGet(crow::Response &res, const crow::Request &req,
558                const std::vector<std::string> &params) override
559     {
560         BMCWEB_LOG_DEBUG << "Get list of available boards.";
561         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
562         res.jsonValue = Node::json;
563         crow::connections::systemBus->async_method_call(
564             [asyncResp](const boost::system::error_code ec,
565                         const std::vector<std::string> &resp) {
566                 if (ec)
567                 {
568                     asyncResp->res.result(
569                         boost::beast::http::status::internal_server_error);
570                     return;
571                 }
572                 BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards.";
573 
574                 // ... prepare json array with appropriate @odata.id links
575                 nlohmann::json &boardArray =
576                     asyncResp->res.jsonValue["Members"];
577                 boardArray = nlohmann::json::array();
578 
579                 // Iterate over all retrieved ObjectPaths.
580                 for (const std::string &objpath : resp)
581                 {
582                     std::size_t lastPos = objpath.rfind("/");
583                     if (lastPos != std::string::npos)
584                     {
585                         boardArray.push_back(
586                             {{"@odata.id", "/redfish/v1/Systems/" +
587                                                objpath.substr(lastPos + 1)}});
588                     }
589                 }
590 
591                 asyncResp->res.jsonValue["Members@odata.count"] =
592                     boardArray.size();
593             },
594             "xyz.openbmc_project.ObjectMapper",
595             "/xyz/openbmc_project/object_mapper",
596             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
597             "/xyz/openbmc_project/inventory", int32_t(0),
598             std::array<const char *, 1>{
599                 "xyz.openbmc_project.Inventory.Item.Board"});
600     }
601 };
602 
603 /**
604  * SystemActionsReset class supports handle POST method for Reset action.
605  * The class retrieves and sends data directly to D-Bus.
606  */
607 class SystemActionsReset : public Node
608 {
609   public:
610     SystemActionsReset(CrowApp &app) :
611         Node(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/",
612              std::string())
613     {
614         entityPrivileges = {
615             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
616     }
617 
618   private:
619     /**
620      * Function handles POST method request.
621      * Analyzes POST body message before sends Reset request data to D-Bus.
622      */
623     void doPost(crow::Response &res, const crow::Request &req,
624                 const std::vector<std::string> &params) override
625     {
626         // Parse JSON request body.
627         nlohmann::json post;
628         if (!json_util::processJsonFromRequest(res, req, post))
629         {
630             return;
631         }
632 
633         auto asyncResp = std::make_shared<AsyncResp>(res);
634 
635         for (const auto &item : post.items())
636         {
637             if (item.key() == "ResetType")
638             {
639                 const std::string *reqResetType =
640                     item.value().get_ptr<const std::string *>();
641                 if (reqResetType == nullptr)
642                 {
643                     res.result(boost::beast::http::status::bad_request);
644                     messages::addMessageToErrorJson(
645                         asyncResp->res.jsonValue,
646                         messages::actionParameterValueFormatError(
647                             item.value().dump(), "ResetType",
648                             "ComputerSystem.Reset"));
649                     res.end();
650                     return;
651                 }
652 
653                 if (*reqResetType == "ForceOff")
654                 {
655                     // Force off acts on the chassis
656                     crow::connections::systemBus->async_method_call(
657                         [asyncResp](const boost::system::error_code ec) {
658                             if (ec)
659                             {
660                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
661                                                  << ec;
662                                 asyncResp->res.result(
663                                     boost::beast::http::status::
664                                         internal_server_error);
665                                 return;
666                             }
667                             // TODO Consider support polling mechanism to verify
668                             // status of host and chassis after execute the
669                             // requested action.
670                             BMCWEB_LOG_DEBUG << "Response with no content";
671                             asyncResp->res.result(
672                                 boost::beast::http::status::no_content);
673                         },
674                         "xyz.openbmc_project.State.Chassis",
675                         "/xyz/openbmc_project/state/chassis0",
676                         "org.freedesktop.DBus.Properties", "Set",
677                         "RequestedPowerTransition",
678                         "xyz.openbmc_project.State.Chassis",
679                         sdbusplus::message::variant<std::string>{
680                             "xyz.openbmc_project.State.Chassis.Transition."
681                             "Off"});
682                     return;
683                 }
684                 // all other actions operate on the host
685                 std::string command;
686                 // Execute Reset Action regarding to each reset type.
687                 if (*reqResetType == "On")
688                 {
689                     command = "xyz.openbmc_project.State.Host.Transition.On";
690                 }
691                 else if (*reqResetType == "GracefulShutdown")
692                 {
693                     command = "xyz.openbmc_project.State.Host.Transition.Off";
694                 }
695                 else if (*reqResetType == "GracefulRestart")
696                 {
697                     command =
698                         "xyz.openbmc_project.State.Host.Transition.Reboot";
699                 }
700                 else
701                 {
702                     res.result(boost::beast::http::status::bad_request);
703                     messages::addMessageToErrorJson(
704                         asyncResp->res.jsonValue,
705                         messages::actionParameterUnknown("Reset",
706                                                          *reqResetType));
707                     res.end();
708                     return;
709                 }
710 
711                 crow::connections::systemBus->async_method_call(
712                     [asyncResp](const boost::system::error_code ec) {
713                         if (ec)
714                         {
715                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
716                             asyncResp->res.result(boost::beast::http::status::
717                                                       internal_server_error);
718                             return;
719                         }
720                         // TODO Consider support polling mechanism to verify
721                         // status of host and chassis after execute the
722                         // requested action.
723                         BMCWEB_LOG_DEBUG << "Response with no content";
724                         asyncResp->res.result(
725                             boost::beast::http::status::no_content);
726                     },
727                     "xyz.openbmc_project.State.Host",
728                     "/xyz/openbmc_project/state/host0",
729                     "org.freedesktop.DBus.Properties", "Set",
730                     "RequestedHostTransition", "xyz.openbmc_project.State.Host",
731                     sdbusplus::message::variant<std::string>{command});
732             }
733             else
734             {
735                 messages::addMessageToErrorJson(
736                     asyncResp->res.jsonValue,
737                     messages::actionParameterUnknown("ComputerSystem.Reset",
738                                                      item.key()));
739             }
740         }
741     }
742 };
743 
744 /**
745  * Systems derived class for delivering Computer Systems Schema.
746  */
747 class Systems : public Node
748 {
749   public:
750     /*
751      * Default Constructor
752      */
753     Systems(CrowApp &app) :
754         Node(app, "/redfish/v1/Systems/<str>/", std::string())
755     {
756         Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
757         Node::json["@odata.context"] =
758             "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
759         Node::json["SystemType"] = "Physical";
760         Node::json["Description"] = "Computer System";
761         Node::json["Boot"]["BootSourceOverrideEnabled"] =
762             "Disabled"; // TODO(Dawid), get real boot data
763         Node::json["Boot"]["BootSourceOverrideTarget"] =
764             "None"; // TODO(Dawid), get real boot data
765         Node::json["Boot"]["BootSourceOverrideMode"] =
766             "Legacy"; // TODO(Dawid), get real boot data
767         Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] =
768             {"None",      "Pxe",       "Hdd", "Cd",
769              "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot
770                                                // data
771         Node::json["ProcessorSummary"]["Count"] = int(0);
772         Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
773         Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
774         Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
775         entityPrivileges = {
776             {boost::beast::http::verb::get, {{"Login"}}},
777             {boost::beast::http::verb::head, {{"Login"}}},
778             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
779             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
780             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
781             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
782     }
783 
784   private:
785     /**
786      * Functions triggers appropriate requests on DBus
787      */
788     void doGet(crow::Response &res, const crow::Request &req,
789                const std::vector<std::string> &params) override
790     {
791         // Check if there is required param, truly entering this shall be
792         // impossible
793         if (params.size() != 1)
794         {
795             res.result(boost::beast::http::status::internal_server_error);
796             res.end();
797             return;
798         }
799 
800         const std::string &name = params[0];
801 
802         // TODO Need to support ForceRestart.
803         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
804             {"target",
805              "/redfish/v1/Systems/" + name + "/Actions/ComputerSystem.Reset"},
806             {"ResetType@Redfish.AllowableValues",
807              {"On", "ForceOff", "GracefulRestart", "GracefulShutdown"}}};
808 
809         auto asyncResp = std::make_shared<AsyncResp>(res);
810 
811         getLedGroupIdentify(
812             asyncResp,
813             [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) {
814                 if (asserted)
815                 {
816                     // If led group is asserted, then another call is needed to
817                     // get led status
818                     getLedIdentify(
819                         aResp, [](const std::string &ledStatus,
820                                   const std::shared_ptr<AsyncResp> &aResp) {
821                             if (!ledStatus.empty())
822                             {
823                                 aResp->res.jsonValue["IndicatorLED"] =
824                                     ledStatus;
825                             }
826                         });
827                 }
828                 else
829                 {
830                     aResp->res.jsonValue["IndicatorLED"] = "Off";
831                 }
832             });
833         getComputerSystem(asyncResp, name);
834         getHostState(asyncResp);
835     }
836 
837     void doPatch(crow::Response &res, const crow::Request &req,
838                  const std::vector<std::string> &params) override
839     {
840         // Check if there is required param, truly entering this shall be
841         // impossible
842         auto asyncResp = std::make_shared<AsyncResp>(res);
843         if (params.size() != 1)
844         {
845             res.result(boost::beast::http::status::internal_server_error);
846             return;
847         }
848         // Parse JSON request body
849         nlohmann::json patch;
850         if (!json_util::processJsonFromRequest(res, req, patch))
851         {
852             return;
853         }
854 
855         const std::string &name = params[0];
856 
857         res.jsonValue = Node::json;
858         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
859 
860         for (const auto &item : patch.items())
861         {
862             if (item.key() == "IndicatorLed")
863             {
864                 const std::string *reqLedState =
865                     item.value().get_ptr<const std::string *>();
866                 if (reqLedState == nullptr)
867                 {
868                     messages::addMessageToErrorJson(
869                         asyncResp->res.jsonValue,
870                         messages::propertyValueFormatError(item.value().dump(),
871                                                            item.key()));
872                     return;
873                 }
874 
875                 // Verify key value
876                 std::string dbusLedState;
877                 if (*reqLedState == "On")
878                 {
879                     dbusLedState =
880                         "xyz.openbmc_project.Led.Physical.Action.Lit";
881                 }
882                 else if (*reqLedState == "Blink")
883                 {
884                     dbusLedState =
885                         "xyz.openbmc_project.Led.Physical.Action.Blinking";
886                 }
887                 else if (*reqLedState == "Off")
888                 {
889                     dbusLedState =
890                         "xyz.openbmc_project.Led.Physical.Action.Off";
891                 }
892                 else
893                 {
894                     messages::addMessageToJsonRoot(
895                         res.jsonValue, messages::propertyValueNotInList(
896                                            *reqLedState, "IndicatorLED"));
897                     return;
898                 }
899 
900                 getHostState(asyncResp);
901                 getComputerSystem(asyncResp, name);
902 
903                 // Update led group
904                 BMCWEB_LOG_DEBUG << "Update led group.";
905                 crow::connections::systemBus->async_method_call(
906                     [asyncResp{std::move(asyncResp)}](
907                         const boost::system::error_code ec) {
908                         if (ec)
909                         {
910                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
911                             asyncResp->res.result(boost::beast::http::status::
912                                                       internal_server_error);
913                             return;
914                         }
915                         BMCWEB_LOG_DEBUG << "Led group update done.";
916                     },
917                     "xyz.openbmc_project.LED.GroupManager",
918                     "/xyz/openbmc_project/led/groups/enclosure_identify",
919                     "org.freedesktop.DBus.Properties", "Set",
920                     "xyz.openbmc_project.Led.Group", "Asserted",
921                     sdbusplus::message::variant<bool>(
922                         (dbusLedState ==
923                                  "xyz.openbmc_project.Led.Physical.Action.Off"
924                              ? false
925                              : true)));
926                 // Update identify led status
927                 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
928                 crow::connections::systemBus->async_method_call(
929                     [asyncResp{std::move(asyncResp)},
930                      reqLedState{std::move(*reqLedState)}](
931                         const boost::system::error_code ec) {
932                         if (ec)
933                         {
934                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
935                             asyncResp->res.result(boost::beast::http::status::
936                                                       internal_server_error);
937                             return;
938                         }
939                         BMCWEB_LOG_DEBUG << "Led state update done.";
940                         asyncResp->res.jsonValue["IndicatorLED"] =
941                             std::move(reqLedState);
942                     },
943                     "xyz.openbmc_project.LED.Controller.identify",
944                     "/xyz/openbmc_project/led/physical/identify",
945                     "org.freedesktop.DBus.Properties", "Set",
946                     "xyz.openbmc_project.Led.Physical", "State",
947                     sdbusplus::message::variant<std::string>(dbusLedState));
948             }
949             else
950             {
951                 messages::addMessageToErrorJson(
952                     asyncResp->res.jsonValue,
953                     messages::propertyNotWritable(item.key()));
954                 return;
955             }
956         }
957     }
958 };
959 } // namespace redfish
960