xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision b7a08d042222796f8803311c05e5029b10144d6a)
19c310685SBorawski.Lukasz /*
29c310685SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation
39c310685SBorawski.Lukasz //
49c310685SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License");
59c310685SBorawski.Lukasz // you may not use this file except in compliance with the License.
69c310685SBorawski.Lukasz // You may obtain a copy of the License at
79c310685SBorawski.Lukasz //
89c310685SBorawski.Lukasz //      http://www.apache.org/licenses/LICENSE-2.0
99c310685SBorawski.Lukasz //
109c310685SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software
119c310685SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS,
129c310685SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c310685SBorawski.Lukasz // See the License for the specific language governing permissions and
149c310685SBorawski.Lukasz // limitations under the License.
159c310685SBorawski.Lukasz */
169c310685SBorawski.Lukasz #pragma once
179c310685SBorawski.Lukasz 
189c310685SBorawski.Lukasz #include "node.hpp"
199c310685SBorawski.Lukasz 
205b4aa86bSJames Feist #include <boost/algorithm/string/replace.hpp>
215b4aa86bSJames Feist #include <dbus_utility.hpp>
225b4aa86bSJames Feist 
231abe55efSEd Tanous namespace redfish
241abe55efSEd Tanous {
25ed5befbdSJennifer Lee 
26ed5befbdSJennifer Lee /**
27ed5befbdSJennifer Lee  * ManagerActionsReset class supports handle POST method for Reset action.
28ed5befbdSJennifer Lee  * The class retrieves and sends data directly to dbus.
29ed5befbdSJennifer Lee  */
30ed5befbdSJennifer Lee class ManagerActionsReset : public Node
31ed5befbdSJennifer Lee {
32ed5befbdSJennifer Lee   public:
33ed5befbdSJennifer Lee     ManagerActionsReset(CrowApp& app) :
34ed5befbdSJennifer Lee         Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/")
35ed5befbdSJennifer Lee     {
36ed5befbdSJennifer Lee         entityPrivileges = {
37ed5befbdSJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
38ed5befbdSJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
39ed5befbdSJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
40ed5befbdSJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
41ed5befbdSJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
42ed5befbdSJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
43ed5befbdSJennifer Lee     }
44ed5befbdSJennifer Lee 
45ed5befbdSJennifer Lee   private:
46ed5befbdSJennifer Lee     /**
47ed5befbdSJennifer Lee      * Function handles POST method request.
48ed5befbdSJennifer Lee      * Analyzes POST body message before sends Reset request data to dbus.
49ed5befbdSJennifer Lee      * OpenBMC allows for ResetType is GracefulRestart only.
50ed5befbdSJennifer Lee      */
51ed5befbdSJennifer Lee     void doPost(crow::Response& res, const crow::Request& req,
52ed5befbdSJennifer Lee                 const std::vector<std::string>& params) override
53ed5befbdSJennifer Lee     {
54ed5befbdSJennifer Lee         std::string resetType;
55ed5befbdSJennifer Lee 
56ed5befbdSJennifer Lee         if (!json_util::readJson(req, res, "ResetType", resetType))
57ed5befbdSJennifer Lee         {
58ed5befbdSJennifer Lee             return;
59ed5befbdSJennifer Lee         }
60ed5befbdSJennifer Lee 
61ed5befbdSJennifer Lee         if (resetType != "GracefulRestart")
62ed5befbdSJennifer Lee         {
63ed5befbdSJennifer Lee             res.result(boost::beast::http::status::bad_request);
64ed5befbdSJennifer Lee             messages::actionParameterNotSupported(res, resetType, "ResetType");
65ed5befbdSJennifer Lee             BMCWEB_LOG_ERROR << "Request incorrect action parameter: "
66ed5befbdSJennifer Lee                              << resetType;
67ed5befbdSJennifer Lee             res.end();
68ed5befbdSJennifer Lee             return;
69ed5befbdSJennifer Lee         }
70ed5befbdSJennifer Lee         doBMCGracefulRestart(res, req, params);
71ed5befbdSJennifer Lee     }
72ed5befbdSJennifer Lee 
73ed5befbdSJennifer Lee     /**
74ed5befbdSJennifer Lee      * Function transceives data with dbus directly.
75ed5befbdSJennifer Lee      * All BMC state properties will be retrieved before sending reset request.
76ed5befbdSJennifer Lee      */
77ed5befbdSJennifer Lee     void doBMCGracefulRestart(crow::Response& res, const crow::Request& req,
78ed5befbdSJennifer Lee                               const std::vector<std::string>& params)
79ed5befbdSJennifer Lee     {
80ed5befbdSJennifer Lee         const char* processName = "xyz.openbmc_project.State.BMC";
81ed5befbdSJennifer Lee         const char* objectPath = "/xyz/openbmc_project/state/bmc0";
82ed5befbdSJennifer Lee         const char* interfaceName = "xyz.openbmc_project.State.BMC";
83ed5befbdSJennifer Lee         const std::string& propertyValue =
84ed5befbdSJennifer Lee             "xyz.openbmc_project.State.BMC.Transition.Reboot";
85ed5befbdSJennifer Lee         const char* destProperty = "RequestedBMCTransition";
86ed5befbdSJennifer Lee 
87ed5befbdSJennifer Lee         // Create the D-Bus variant for D-Bus call.
88ed5befbdSJennifer Lee         VariantType dbusPropertyValue(propertyValue);
89ed5befbdSJennifer Lee 
90ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
91ed5befbdSJennifer Lee 
92ed5befbdSJennifer Lee         crow::connections::systemBus->async_method_call(
93ed5befbdSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
94ed5befbdSJennifer Lee                 // Use "Set" method to set the property value.
95ed5befbdSJennifer Lee                 if (ec)
96ed5befbdSJennifer Lee                 {
97ed5befbdSJennifer Lee                     BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec;
98ed5befbdSJennifer Lee                     messages::internalError(asyncResp->res);
99ed5befbdSJennifer Lee                     return;
100ed5befbdSJennifer Lee                 }
101ed5befbdSJennifer Lee 
102ed5befbdSJennifer Lee                 messages::success(asyncResp->res);
103ed5befbdSJennifer Lee             },
104ed5befbdSJennifer Lee             processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
105ed5befbdSJennifer Lee             interfaceName, destProperty, dbusPropertyValue);
106ed5befbdSJennifer Lee     }
107ed5befbdSJennifer Lee };
108ed5befbdSJennifer Lee 
1095b4aa86bSJames Feist static constexpr const char* objectManagerIface =
1105b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
1115b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
1125b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1135b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
1145b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
115*b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface =
116*b7a08d04SJames Feist     "xyz.openbmc_project.Configuration.Stepwise";
1179c310685SBorawski.Lukasz 
1185b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection,
1195b4aa86bSJames Feist                              const std::string& path,
1205b4aa86bSJames Feist                              std::shared_ptr<AsyncResp> asyncResp)
1215b4aa86bSJames Feist {
1225b4aa86bSJames Feist 
1235b4aa86bSJames Feist     crow::connections::systemBus->async_method_call(
1245b4aa86bSJames Feist         [asyncResp](const boost::system::error_code ec,
1255b4aa86bSJames Feist                     const dbus::utility::ManagedObjectType& managedObj) {
1265b4aa86bSJames Feist             if (ec)
1275b4aa86bSJames Feist             {
1285b4aa86bSJames Feist                 BMCWEB_LOG_ERROR << ec;
1295b4aa86bSJames Feist                 asyncResp->res.jsonValue.clear();
130f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1315b4aa86bSJames Feist                 return;
1325b4aa86bSJames Feist             }
1335b4aa86bSJames Feist             nlohmann::json& configRoot =
1345b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
1355b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
1365b4aa86bSJames Feist             fans["@odata.type"] = "#OemManager.FanControllers";
1375b4aa86bSJames Feist             fans["@odata.context"] =
1385b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanControllers";
1395b4aa86bSJames Feist             fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
1405b4aa86bSJames Feist                                 "Fan/FanControllers";
1415b4aa86bSJames Feist 
1425b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
1435b4aa86bSJames Feist             pids["@odata.type"] = "#OemManager.PidControllers";
1445b4aa86bSJames Feist             pids["@odata.context"] =
1455b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.PidControllers";
1465b4aa86bSJames Feist             pids["@odata.id"] =
1475b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
1485b4aa86bSJames Feist 
149*b7a08d04SJames Feist             nlohmann::json& stepwise = configRoot["StepwiseControllers"];
150*b7a08d04SJames Feist             stepwise["@odata.type"] = "#OemManager.StepwiseControllers";
151*b7a08d04SJames Feist             stepwise["@odata.context"] =
152*b7a08d04SJames Feist                 "/redfish/v1/$metadata#OemManager.StepwiseControllers";
153*b7a08d04SJames Feist             stepwise["@odata.id"] =
154*b7a08d04SJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers";
155*b7a08d04SJames Feist 
1565b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
1575b4aa86bSJames Feist             zones["@odata.id"] =
1585b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
1595b4aa86bSJames Feist             zones["@odata.type"] = "#OemManager.FanZones";
1605b4aa86bSJames Feist             zones["@odata.context"] =
1615b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanZones";
1625b4aa86bSJames Feist             configRoot["@odata.id"] =
1635b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
1645b4aa86bSJames Feist             configRoot["@odata.type"] = "#OemManager.Fan";
1655b4aa86bSJames Feist             configRoot["@odata.context"] =
1665b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.Fan";
1675b4aa86bSJames Feist 
1685b4aa86bSJames Feist             bool propertyError = false;
1695b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
1705b4aa86bSJames Feist             {
1715b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
1725b4aa86bSJames Feist                 {
1735b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
174*b7a08d04SJames Feist                         intfPair.first != pidZoneConfigurationIface &&
175*b7a08d04SJames Feist                         intfPair.first != stepwiseConfigurationIface)
1765b4aa86bSJames Feist                     {
1775b4aa86bSJames Feist                         continue;
1785b4aa86bSJames Feist                     }
1795b4aa86bSJames Feist                     auto findName = intfPair.second.find("Name");
1805b4aa86bSJames Feist                     if (findName == intfPair.second.end())
1815b4aa86bSJames Feist                     {
1825b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Field missing Name";
183a08b46ccSJason M. Bills                         messages::internalError(asyncResp->res);
1845b4aa86bSJames Feist                         return;
1855b4aa86bSJames Feist                     }
1865b4aa86bSJames Feist                     const std::string* namePtr =
1871b6b96c5SEd Tanous                         sdbusplus::message::variant_ns::get_if<std::string>(
1881b6b96c5SEd Tanous                             &findName->second);
1895b4aa86bSJames Feist                     if (namePtr == nullptr)
1905b4aa86bSJames Feist                     {
1915b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Name Field illegal";
192*b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
1935b4aa86bSJames Feist                         return;
1945b4aa86bSJames Feist                     }
1955b4aa86bSJames Feist 
1965b4aa86bSJames Feist                     std::string name = *namePtr;
1975b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
198*b7a08d04SJames Feist                     nlohmann::json* config = nullptr;
1995b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
2005b4aa86bSJames Feist                     {
2015b4aa86bSJames Feist                         std::string chassis;
2025b4aa86bSJames Feist                         if (!dbus::utility::getNthStringFromPath(
2035b4aa86bSJames Feist                                 pathPair.first.str, 5, chassis))
2045b4aa86bSJames Feist                         {
2055b4aa86bSJames Feist                             chassis = "#IllegalValue";
2065b4aa86bSJames Feist                         }
2075b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
2085b4aa86bSJames Feist                         zone["Chassis"] = {
2095b4aa86bSJames Feist                             {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
2105b4aa86bSJames Feist                         zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
2115b4aa86bSJames Feist                                             "OpenBmc/Fan/FanZones/" +
2125b4aa86bSJames Feist                                             name;
2135b4aa86bSJames Feist                         zone["@odata.type"] = "#OemManager.FanZone";
2145b4aa86bSJames Feist                         zone["@odata.context"] =
2155b4aa86bSJames Feist                             "/redfish/v1/$metadata#OemManager.FanZone";
216*b7a08d04SJames Feist                         config = &zone;
2175b4aa86bSJames Feist                     }
2185b4aa86bSJames Feist 
219*b7a08d04SJames Feist                     else if (intfPair.first == stepwiseConfigurationIface)
2205b4aa86bSJames Feist                     {
221*b7a08d04SJames Feist                         nlohmann::json& controller = stepwise[name];
222*b7a08d04SJames Feist                         config = &controller;
2235b4aa86bSJames Feist 
224*b7a08d04SJames Feist                         controller["@odata.id"] =
225*b7a08d04SJames Feist                             "/redfish/v1/Managers/bmc#/Oem/"
226*b7a08d04SJames Feist                             "OpenBmc/Fan/StepwiseControllers/" +
227*b7a08d04SJames Feist                             std::string(name);
228*b7a08d04SJames Feist                         controller["@odata.type"] =
229*b7a08d04SJames Feist                             "#OemManager.StepwiseController";
230*b7a08d04SJames Feist 
231*b7a08d04SJames Feist                         controller["@odata.context"] =
232*b7a08d04SJames Feist                             "/redfish/v1/"
233*b7a08d04SJames Feist                             "$metadata#OemManager.StepwiseController";
2345b4aa86bSJames Feist                     }
2355b4aa86bSJames Feist 
2365b4aa86bSJames Feist                     // pid and fans are off the same configuration
237*b7a08d04SJames Feist                     else if (intfPair.first == pidConfigurationIface)
2385b4aa86bSJames Feist                     {
2395b4aa86bSJames Feist                         const std::string* classPtr = nullptr;
2405b4aa86bSJames Feist                         auto findClass = intfPair.second.find("Class");
2415b4aa86bSJames Feist                         if (findClass != intfPair.second.end())
2425b4aa86bSJames Feist                         {
243*b7a08d04SJames Feist                             classPtr = sdbusplus::message::variant_ns::get_if<
2441b6b96c5SEd Tanous                                 std::string>(&findClass->second);
2455b4aa86bSJames Feist                         }
2465b4aa86bSJames Feist                         if (classPtr == nullptr)
2475b4aa86bSJames Feist                         {
2485b4aa86bSJames Feist                             BMCWEB_LOG_ERROR << "Pid Class Field illegal";
249a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
2505b4aa86bSJames Feist                             return;
2515b4aa86bSJames Feist                         }
2525b4aa86bSJames Feist                         bool isFan = *classPtr == "fan";
2535b4aa86bSJames Feist                         nlohmann::json& element =
2545b4aa86bSJames Feist                             isFan ? fans[name] : pids[name];
255*b7a08d04SJames Feist                         config = &element;
2565b4aa86bSJames Feist                         if (isFan)
2575b4aa86bSJames Feist                         {
2585b4aa86bSJames Feist                             element["@odata.id"] =
2595b4aa86bSJames Feist                                 "/redfish/v1/Managers/bmc#/Oem/"
2605b4aa86bSJames Feist                                 "OpenBmc/Fan/FanControllers/" +
2615b4aa86bSJames Feist                                 std::string(name);
2625b4aa86bSJames Feist                             element["@odata.type"] =
2635b4aa86bSJames Feist                                 "#OemManager.FanController";
2645b4aa86bSJames Feist 
2655b4aa86bSJames Feist                             element["@odata.context"] =
2665b4aa86bSJames Feist                                 "/redfish/v1/"
2675b4aa86bSJames Feist                                 "$metadata#OemManager.FanController";
2685b4aa86bSJames Feist                         }
2695b4aa86bSJames Feist                         else
2705b4aa86bSJames Feist                         {
2715b4aa86bSJames Feist                             element["@odata.id"] =
2725b4aa86bSJames Feist                                 "/redfish/v1/Managers/bmc#/Oem/"
2735b4aa86bSJames Feist                                 "OpenBmc/Fan/PidControllers/" +
2745b4aa86bSJames Feist                                 std::string(name);
2755b4aa86bSJames Feist                             element["@odata.type"] =
2765b4aa86bSJames Feist                                 "#OemManager.PidController";
2775b4aa86bSJames Feist                             element["@odata.context"] =
2785b4aa86bSJames Feist                                 "/redfish/v1/$metadata"
2795b4aa86bSJames Feist                                 "#OemManager.PidController";
2805b4aa86bSJames Feist                         }
281*b7a08d04SJames Feist                     }
282*b7a08d04SJames Feist                     else
283*b7a08d04SJames Feist                     {
284*b7a08d04SJames Feist                         BMCWEB_LOG_ERROR << "Unexpected configuration";
285*b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
286*b7a08d04SJames Feist                         return;
287*b7a08d04SJames Feist                     }
288*b7a08d04SJames Feist 
289*b7a08d04SJames Feist                     // used for making maps out of 2 vectors
290*b7a08d04SJames Feist                     const std::vector<double>* keys = nullptr;
291*b7a08d04SJames Feist                     const std::vector<double>* values = nullptr;
292*b7a08d04SJames Feist 
293*b7a08d04SJames Feist                     for (const auto& propertyPair : intfPair.second)
294*b7a08d04SJames Feist                     {
295*b7a08d04SJames Feist                         if (propertyPair.first == "Type" ||
296*b7a08d04SJames Feist                             propertyPair.first == "Class" ||
297*b7a08d04SJames Feist                             propertyPair.first == "Name")
298*b7a08d04SJames Feist                         {
299*b7a08d04SJames Feist                             continue;
300*b7a08d04SJames Feist                         }
301*b7a08d04SJames Feist 
302*b7a08d04SJames Feist                         // zones
303*b7a08d04SJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
304*b7a08d04SJames Feist                         {
305*b7a08d04SJames Feist                             const double* ptr =
306*b7a08d04SJames Feist                                 sdbusplus::message::variant_ns::get_if<double>(
307*b7a08d04SJames Feist                                     &propertyPair.second);
308*b7a08d04SJames Feist                             if (ptr == nullptr)
309*b7a08d04SJames Feist                             {
310*b7a08d04SJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
311*b7a08d04SJames Feist                                                  << propertyPair.first;
312*b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
313*b7a08d04SJames Feist                                 return;
314*b7a08d04SJames Feist                             }
315*b7a08d04SJames Feist                             (*config)[propertyPair.first] = *ptr;
316*b7a08d04SJames Feist                         }
317*b7a08d04SJames Feist 
318*b7a08d04SJames Feist                         if (intfPair.first == stepwiseConfigurationIface)
319*b7a08d04SJames Feist                         {
320*b7a08d04SJames Feist                             if (propertyPair.first == "Reading" ||
321*b7a08d04SJames Feist                                 propertyPair.first == "Output")
322*b7a08d04SJames Feist                             {
323*b7a08d04SJames Feist                                 const std::vector<double>* ptr =
324*b7a08d04SJames Feist                                     sdbusplus::message::variant_ns::get_if<
325*b7a08d04SJames Feist                                         std::vector<double>>(
326*b7a08d04SJames Feist                                         &propertyPair.second);
327*b7a08d04SJames Feist 
328*b7a08d04SJames Feist                                 if (ptr == nullptr)
329*b7a08d04SJames Feist                                 {
330*b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
331*b7a08d04SJames Feist                                                      << propertyPair.first;
332*b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
333*b7a08d04SJames Feist                                     return;
334*b7a08d04SJames Feist                                 }
335*b7a08d04SJames Feist 
336*b7a08d04SJames Feist                                 if (propertyPair.first == "Reading")
337*b7a08d04SJames Feist                                 {
338*b7a08d04SJames Feist                                     keys = ptr;
339*b7a08d04SJames Feist                                 }
340*b7a08d04SJames Feist                                 else
341*b7a08d04SJames Feist                                 {
342*b7a08d04SJames Feist                                     values = ptr;
343*b7a08d04SJames Feist                                 }
344*b7a08d04SJames Feist                                 if (keys && values)
345*b7a08d04SJames Feist                                 {
346*b7a08d04SJames Feist                                     if (keys->size() != values->size())
347*b7a08d04SJames Feist                                     {
348*b7a08d04SJames Feist                                         BMCWEB_LOG_ERROR
349*b7a08d04SJames Feist                                             << "Reading and Output size don't "
350*b7a08d04SJames Feist                                                "match ";
351*b7a08d04SJames Feist                                         messages::internalError(asyncResp->res);
352*b7a08d04SJames Feist                                         return;
353*b7a08d04SJames Feist                                     }
354*b7a08d04SJames Feist                                     nlohmann::json& steps = (*config)["Steps"];
355*b7a08d04SJames Feist                                     steps = nlohmann::json::array();
356*b7a08d04SJames Feist                                     for (size_t ii = 0; ii < keys->size(); ii++)
357*b7a08d04SJames Feist                                     {
358*b7a08d04SJames Feist                                         steps.push_back(
359*b7a08d04SJames Feist                                             {{"Target", (*keys)[ii]},
360*b7a08d04SJames Feist                                              {"Output", (*values)[ii]}});
361*b7a08d04SJames Feist                                     }
362*b7a08d04SJames Feist                                 }
363*b7a08d04SJames Feist                             }
364*b7a08d04SJames Feist                             if (propertyPair.first == "NegativeHysteresis" ||
365*b7a08d04SJames Feist                                 propertyPair.first == "PositiveHysteresis")
366*b7a08d04SJames Feist                             {
367*b7a08d04SJames Feist                                 const double* ptr =
368*b7a08d04SJames Feist                                     sdbusplus::message::variant_ns::get_if<
369*b7a08d04SJames Feist                                         double>(&propertyPair.second);
370*b7a08d04SJames Feist                                 if (ptr == nullptr)
371*b7a08d04SJames Feist                                 {
372*b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
373*b7a08d04SJames Feist                                                      << propertyPair.first;
374*b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
375*b7a08d04SJames Feist                                     return;
376*b7a08d04SJames Feist                                 }
377*b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
378*b7a08d04SJames Feist                             }
379*b7a08d04SJames Feist                         }
380*b7a08d04SJames Feist 
381*b7a08d04SJames Feist                         // pid and fans are off the same configuration
382*b7a08d04SJames Feist                         if (intfPair.first == pidConfigurationIface ||
383*b7a08d04SJames Feist                             intfPair.first == stepwiseConfigurationIface)
384*b7a08d04SJames Feist                         {
3855b4aa86bSJames Feist 
3865b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
3875b4aa86bSJames Feist                             {
3885b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
3891b6b96c5SEd Tanous                                     sdbusplus::message::variant_ns::get_if<
3901b6b96c5SEd Tanous                                         std::vector<std::string>>(
3911b6b96c5SEd Tanous                                         &propertyPair.second);
3925b4aa86bSJames Feist 
3935b4aa86bSJames Feist                                 if (inputs == nullptr)
3945b4aa86bSJames Feist                                 {
3955b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR
3965b4aa86bSJames Feist                                         << "Zones Pid Field Illegal";
397a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
3985b4aa86bSJames Feist                                     return;
3995b4aa86bSJames Feist                                 }
400*b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
4015b4aa86bSJames Feist                                 data = nlohmann::json::array();
4025b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
4035b4aa86bSJames Feist                                 {
4045b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
4055b4aa86bSJames Feist                                     data.push_back(
4065b4aa86bSJames Feist                                         {{"@odata.id",
4075b4aa86bSJames Feist                                           "/redfish/v1/Managers/bmc#/Oem/"
4085b4aa86bSJames Feist                                           "OpenBmc/Fan/FanZones/" +
4095b4aa86bSJames Feist                                               itemCopy}});
4105b4aa86bSJames Feist                                 }
4115b4aa86bSJames Feist                             }
4125b4aa86bSJames Feist                             // todo(james): may never happen, but this
4135b4aa86bSJames Feist                             // assumes configuration data referenced in the
4145b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
4155b4aa86bSJames Feist                             // could add another loop to cover all cases,
4165b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
4175b4aa86bSJames Feist                             // bit
4185b4aa86bSJames Feist 
4195b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
4205b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
4215b4aa86bSJames Feist                             {
422*b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
4235b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
4241b6b96c5SEd Tanous                                     sdbusplus::message::variant_ns::get_if<
4251b6b96c5SEd Tanous                                         std::vector<std::string>>(
4261b6b96c5SEd Tanous                                         &propertyPair.second);
4275b4aa86bSJames Feist 
4285b4aa86bSJames Feist                                 if (inputs == nullptr)
4295b4aa86bSJames Feist                                 {
4305b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
4315b4aa86bSJames Feist                                                      << propertyPair.first;
432f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
4335b4aa86bSJames Feist                                     return;
4345b4aa86bSJames Feist                                 }
4355b4aa86bSJames Feist                                 data = *inputs;
4365b4aa86bSJames Feist                             } // doubles
4375b4aa86bSJames Feist                             else if (propertyPair.first ==
4385b4aa86bSJames Feist                                          "FFGainCoefficient" ||
4395b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
4405b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
4415b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
4425b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
4435b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
4445b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
4455b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
4465b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
4475b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
4485b4aa86bSJames Feist                             {
4495b4aa86bSJames Feist                                 const double* ptr =
4501b6b96c5SEd Tanous                                     sdbusplus::message::variant_ns::get_if<
4511b6b96c5SEd Tanous                                         double>(&propertyPair.second);
4525b4aa86bSJames Feist                                 if (ptr == nullptr)
4535b4aa86bSJames Feist                                 {
4545b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
4555b4aa86bSJames Feist                                                      << propertyPair.first;
456f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
4575b4aa86bSJames Feist                                     return;
4585b4aa86bSJames Feist                                 }
459*b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
4605b4aa86bSJames Feist                             }
4615b4aa86bSJames Feist                         }
4625b4aa86bSJames Feist                     }
4635b4aa86bSJames Feist                 }
4645b4aa86bSJames Feist             }
4655b4aa86bSJames Feist         },
4665b4aa86bSJames Feist         connection, path, objectManagerIface, "GetManagedObjects");
4675b4aa86bSJames Feist }
468ca537928SJennifer Lee 
46983ff9ab6SJames Feist enum class CreatePIDRet
47083ff9ab6SJames Feist {
47183ff9ab6SJames Feist     fail,
47283ff9ab6SJames Feist     del,
47383ff9ab6SJames Feist     patch
47483ff9ab6SJames Feist };
47583ff9ab6SJames Feist 
47683ff9ab6SJames Feist static CreatePIDRet createPidInterface(
47783ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
47883ff9ab6SJames Feist     const nlohmann::json& record, const std::string& path,
47983ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
48083ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
48183ff9ab6SJames Feist         output,
48283ff9ab6SJames Feist     std::string& chassis)
48383ff9ab6SJames Feist {
48483ff9ab6SJames Feist 
48583ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
48683ff9ab6SJames Feist     {
48783ff9ab6SJames Feist         if (createNewObject)
48883ff9ab6SJames Feist         {
48983ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
49083ff9ab6SJames Feist                                                        : std::string("fan");
49183ff9ab6SJames Feist             output["Type"] = std::string("Pid");
49283ff9ab6SJames Feist         }
49383ff9ab6SJames Feist         else if (record == nullptr)
49483ff9ab6SJames Feist         {
49583ff9ab6SJames Feist             // delete interface
49683ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
49783ff9ab6SJames Feist                 [response,
49883ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
49983ff9ab6SJames Feist                     if (ec)
50083ff9ab6SJames Feist                     {
50183ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
50283ff9ab6SJames Feist                                          << ec;
50335a62c7cSJason M. Bills                         messages::internalError(response->res);
50483ff9ab6SJames Feist                     }
50583ff9ab6SJames Feist                 },
50683ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
50783ff9ab6SJames Feist                 pidConfigurationIface, "Delete");
50883ff9ab6SJames Feist             return CreatePIDRet::del;
50983ff9ab6SJames Feist         }
51083ff9ab6SJames Feist 
51183ff9ab6SJames Feist         for (auto& field : record.items())
51283ff9ab6SJames Feist         {
51383ff9ab6SJames Feist             if (field.key() == "Zones")
51483ff9ab6SJames Feist             {
51583ff9ab6SJames Feist                 if (!field.value().is_array())
51683ff9ab6SJames Feist                 {
51783ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
51835a62c7cSJason M. Bills                     messages::propertyValueFormatError(
51935a62c7cSJason M. Bills                         response->res, field.value(), field.key());
52083ff9ab6SJames Feist                     return CreatePIDRet::fail;
52183ff9ab6SJames Feist                 }
52283ff9ab6SJames Feist                 std::vector<std::string> inputs;
52383ff9ab6SJames Feist                 for (const auto& odata : field.value().items())
52483ff9ab6SJames Feist                 {
52583ff9ab6SJames Feist                     for (const auto& value : odata.value().items())
52683ff9ab6SJames Feist                     {
52783ff9ab6SJames Feist                         const std::string* path =
52883ff9ab6SJames Feist                             value.value().get_ptr<const std::string*>();
52983ff9ab6SJames Feist                         if (path == nullptr)
53083ff9ab6SJames Feist                         {
53183ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
53283ff9ab6SJames Feist                             messages::propertyValueFormatError(
53335a62c7cSJason M. Bills                                 response->res, field.value().dump(),
53435a62c7cSJason M. Bills                                 field.key());
53583ff9ab6SJames Feist                             return CreatePIDRet::fail;
53683ff9ab6SJames Feist                         }
53783ff9ab6SJames Feist                         std::string input;
53883ff9ab6SJames Feist                         if (!dbus::utility::getNthStringFromPath(*path, 4,
53983ff9ab6SJames Feist                                                                  input))
54083ff9ab6SJames Feist                         {
54183ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Got invalid path " << *path;
54283ff9ab6SJames Feist                             messages::propertyValueFormatError(
54335a62c7cSJason M. Bills                                 response->res, field.value().dump(),
54435a62c7cSJason M. Bills                                 field.key());
54583ff9ab6SJames Feist                             return CreatePIDRet::fail;
54683ff9ab6SJames Feist                         }
54783ff9ab6SJames Feist                         boost::replace_all(input, "_", " ");
54883ff9ab6SJames Feist                         inputs.emplace_back(std::move(input));
54983ff9ab6SJames Feist                     }
55083ff9ab6SJames Feist                 }
55183ff9ab6SJames Feist                 output["Zones"] = std::move(inputs);
55283ff9ab6SJames Feist             }
55383ff9ab6SJames Feist             else if (field.key() == "Inputs" || field.key() == "Outputs")
55483ff9ab6SJames Feist             {
55583ff9ab6SJames Feist                 if (!field.value().is_array())
55683ff9ab6SJames Feist                 {
55783ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
55835a62c7cSJason M. Bills                     messages::propertyValueFormatError(
55935a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
56083ff9ab6SJames Feist                     return CreatePIDRet::fail;
56183ff9ab6SJames Feist                 }
56283ff9ab6SJames Feist                 std::vector<std::string> inputs;
56383ff9ab6SJames Feist                 for (const auto& value : field.value().items())
56483ff9ab6SJames Feist                 {
56583ff9ab6SJames Feist                     const std::string* sensor =
56683ff9ab6SJames Feist                         value.value().get_ptr<const std::string*>();
56783ff9ab6SJames Feist 
56883ff9ab6SJames Feist                     if (sensor == nullptr)
56983ff9ab6SJames Feist                     {
57083ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type "
57183ff9ab6SJames Feist                                          << field.value().dump();
57283ff9ab6SJames Feist                         messages::propertyValueFormatError(
57335a62c7cSJason M. Bills                             response->res, field.value().dump(), field.key());
57483ff9ab6SJames Feist                         return CreatePIDRet::fail;
57583ff9ab6SJames Feist                     }
57683ff9ab6SJames Feist 
57783ff9ab6SJames Feist                     std::string input =
57883ff9ab6SJames Feist                         boost::replace_all_copy(*sensor, "_", " ");
57983ff9ab6SJames Feist                     inputs.push_back(std::move(input));
58083ff9ab6SJames Feist                     // try to find the sensor in the
58183ff9ab6SJames Feist                     // configuration
58283ff9ab6SJames Feist                     if (chassis.empty())
58383ff9ab6SJames Feist                     {
58483ff9ab6SJames Feist                         std::find_if(
58583ff9ab6SJames Feist                             managedObj.begin(), managedObj.end(),
58683ff9ab6SJames Feist                             [&chassis, sensor](const auto& obj) {
58783ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
58883ff9ab6SJames Feist                                                                 *sensor))
58983ff9ab6SJames Feist                                 {
59083ff9ab6SJames Feist                                     return dbus::utility::getNthStringFromPath(
59183ff9ab6SJames Feist                                         obj.first.str, 5, chassis);
59283ff9ab6SJames Feist                                 }
59383ff9ab6SJames Feist                                 return false;
59483ff9ab6SJames Feist                             });
59583ff9ab6SJames Feist                     }
59683ff9ab6SJames Feist                 }
59783ff9ab6SJames Feist                 output[field.key()] = inputs;
59883ff9ab6SJames Feist             }
59983ff9ab6SJames Feist 
60083ff9ab6SJames Feist             // doubles
60183ff9ab6SJames Feist             else if (field.key() == "FFGainCoefficient" ||
60283ff9ab6SJames Feist                      field.key() == "FFOffCoefficient" ||
60383ff9ab6SJames Feist                      field.key() == "ICoefficient" ||
60483ff9ab6SJames Feist                      field.key() == "ILimitMax" || field.key() == "ILimitMin" ||
60583ff9ab6SJames Feist                      field.key() == "OutLimitMax" ||
60683ff9ab6SJames Feist                      field.key() == "OutLimitMin" ||
60783ff9ab6SJames Feist                      field.key() == "PCoefficient" ||
60883ff9ab6SJames Feist                      field.key() == "SetPoint" || field.key() == "SlewNeg" ||
60983ff9ab6SJames Feist                      field.key() == "SlewPos")
61083ff9ab6SJames Feist             {
61183ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
61283ff9ab6SJames Feist                 if (ptr == nullptr)
61383ff9ab6SJames Feist                 {
61483ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
61535a62c7cSJason M. Bills                     messages::propertyValueFormatError(
61635a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
61783ff9ab6SJames Feist                     return CreatePIDRet::fail;
61883ff9ab6SJames Feist                 }
61983ff9ab6SJames Feist                 output[field.key()] = *ptr;
62083ff9ab6SJames Feist             }
62183ff9ab6SJames Feist 
62283ff9ab6SJames Feist             else
62383ff9ab6SJames Feist             {
62483ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
62535a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
62683ff9ab6SJames Feist                 return CreatePIDRet::fail;
62783ff9ab6SJames Feist             }
62883ff9ab6SJames Feist         }
62983ff9ab6SJames Feist     }
63083ff9ab6SJames Feist     else if (type == "FanZones")
63183ff9ab6SJames Feist     {
63283ff9ab6SJames Feist         if (!createNewObject && record == nullptr)
63383ff9ab6SJames Feist         {
63483ff9ab6SJames Feist             // delete interface
63583ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
63683ff9ab6SJames Feist                 [response,
63783ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
63883ff9ab6SJames Feist                     if (ec)
63983ff9ab6SJames Feist                     {
64083ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
64183ff9ab6SJames Feist                                          << ec;
64235a62c7cSJason M. Bills                         messages::internalError(response->res);
64383ff9ab6SJames Feist                     }
64483ff9ab6SJames Feist                 },
64583ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
64683ff9ab6SJames Feist                 pidZoneConfigurationIface, "Delete");
64783ff9ab6SJames Feist             return CreatePIDRet::del;
64883ff9ab6SJames Feist         }
64983ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
65083ff9ab6SJames Feist 
65183ff9ab6SJames Feist         for (auto& field : record.items())
65283ff9ab6SJames Feist         {
65383ff9ab6SJames Feist             if (field.key() == "Chassis")
65483ff9ab6SJames Feist             {
65583ff9ab6SJames Feist                 const std::string* chassisId = nullptr;
65683ff9ab6SJames Feist                 for (const auto& id : field.value().items())
65783ff9ab6SJames Feist                 {
65883ff9ab6SJames Feist                     if (id.key() != "@odata.id")
65983ff9ab6SJames Feist                     {
66083ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << id.key();
66135a62c7cSJason M. Bills                         messages::propertyUnknown(response->res, field.key());
66283ff9ab6SJames Feist                         return CreatePIDRet::fail;
66383ff9ab6SJames Feist                     }
66483ff9ab6SJames Feist                     chassisId = id.value().get_ptr<const std::string*>();
66583ff9ab6SJames Feist                     if (chassisId == nullptr)
66683ff9ab6SJames Feist                     {
66783ff9ab6SJames Feist                         messages::createFailedMissingReqProperties(
66835a62c7cSJason M. Bills                             response->res, field.key());
66983ff9ab6SJames Feist                         return CreatePIDRet::fail;
67083ff9ab6SJames Feist                     }
67183ff9ab6SJames Feist                 }
67283ff9ab6SJames Feist 
67383ff9ab6SJames Feist                 // /refish/v1/chassis/chassis_name/
67483ff9ab6SJames Feist                 if (!dbus::utility::getNthStringFromPath(*chassisId, 3,
67583ff9ab6SJames Feist                                                          chassis))
67683ff9ab6SJames Feist                 {
67783ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId;
67835a62c7cSJason M. Bills                     messages::invalidObject(response->res, *chassisId);
67983ff9ab6SJames Feist                     return CreatePIDRet::fail;
68083ff9ab6SJames Feist                 }
68183ff9ab6SJames Feist             }
68283ff9ab6SJames Feist             else if (field.key() == "FailSafePercent" ||
68383ff9ab6SJames Feist                      field.key() == "MinThermalRpm")
68483ff9ab6SJames Feist             {
68583ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
68683ff9ab6SJames Feist                 if (ptr == nullptr)
68783ff9ab6SJames Feist                 {
68883ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
68935a62c7cSJason M. Bills                     messages::propertyValueFormatError(
69035a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
69183ff9ab6SJames Feist                     return CreatePIDRet::fail;
69283ff9ab6SJames Feist                 }
69383ff9ab6SJames Feist                 output[field.key()] = *ptr;
69483ff9ab6SJames Feist             }
69583ff9ab6SJames Feist             else
69683ff9ab6SJames Feist             {
69783ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
69835a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
69983ff9ab6SJames Feist                 return CreatePIDRet::fail;
70083ff9ab6SJames Feist             }
70183ff9ab6SJames Feist         }
70283ff9ab6SJames Feist     }
70383ff9ab6SJames Feist     else
70483ff9ab6SJames Feist     {
70583ff9ab6SJames Feist         BMCWEB_LOG_ERROR << "Illegal Type " << type;
70635a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
70783ff9ab6SJames Feist         return CreatePIDRet::fail;
70883ff9ab6SJames Feist     }
70983ff9ab6SJames Feist     return CreatePIDRet::patch;
71083ff9ab6SJames Feist }
71183ff9ab6SJames Feist 
7121abe55efSEd Tanous class Manager : public Node
7131abe55efSEd Tanous {
7149c310685SBorawski.Lukasz   public:
7155b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
7161abe55efSEd Tanous     {
7170f74e643SEd Tanous         uuid = app.template getMiddleware<crow::persistent_data::Middleware>()
71855c7b7a2SEd Tanous                    .systemUuid;
719a434f2bdSEd Tanous         entityPrivileges = {
720a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
721e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
722e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
723e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
724e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
725e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
7269c310685SBorawski.Lukasz     }
7279c310685SBorawski.Lukasz 
7289c310685SBorawski.Lukasz   private:
7295b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
7305b4aa86bSJames Feist     {
7315b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
7325b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
7335b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
7345b4aa86bSJames Feist                 if (ec)
7355b4aa86bSJames Feist                 {
7365b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
737f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
7385b4aa86bSJames Feist                     return;
7395b4aa86bSJames Feist                 }
7405b4aa86bSJames Feist 
7415b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
7425b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
7435b4aa86bSJames Feist                     objectMgrPaths;
7446bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
7455b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
7465b4aa86bSJames Feist                 {
7475b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
7485b4aa86bSJames Feist                     {
7496bce33bcSJames Feist                         auto findConnection =
7506bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
7516bce33bcSJames Feist                         if (findConnection != calledConnections.end())
7526bce33bcSJames Feist                         {
7536bce33bcSJames Feist                             break;
7546bce33bcSJames Feist                         }
7555b4aa86bSJames Feist                         for (const std::string& interface :
7565b4aa86bSJames Feist                              connectionGroup.second)
7575b4aa86bSJames Feist                         {
7585b4aa86bSJames Feist                             if (interface == objectManagerIface)
7595b4aa86bSJames Feist                             {
7605b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
7615b4aa86bSJames Feist                                     pathGroup.first;
7625b4aa86bSJames Feist                             }
7635b4aa86bSJames Feist                             // this list is alphabetical, so we
7645b4aa86bSJames Feist                             // should have found the objMgr by now
7655b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
766*b7a08d04SJames Feist                                 interface == pidZoneConfigurationIface ||
767*b7a08d04SJames Feist                                 interface == stepwiseConfigurationIface)
7685b4aa86bSJames Feist                             {
7695b4aa86bSJames Feist                                 auto findObjMgr =
7705b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
7715b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
7725b4aa86bSJames Feist                                 {
7735b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
7745b4aa86bSJames Feist                                                      << "Has no Object Manager";
7755b4aa86bSJames Feist                                     continue;
7765b4aa86bSJames Feist                                 }
7776bce33bcSJames Feist 
7786bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
7796bce33bcSJames Feist 
7805b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
7815b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
7825b4aa86bSJames Feist                                 break;
7835b4aa86bSJames Feist                             }
7845b4aa86bSJames Feist                         }
7855b4aa86bSJames Feist                     }
7865b4aa86bSJames Feist                 }
7875b4aa86bSJames Feist             },
7885b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
7895b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
7905b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
791*b7a08d04SJames Feist             std::array<const char*, 4>{
792*b7a08d04SJames Feist                 pidConfigurationIface, pidZoneConfigurationIface,
793*b7a08d04SJames Feist                 objectManagerIface, stepwiseConfigurationIface});
7945b4aa86bSJames Feist     }
7955b4aa86bSJames Feist 
79655c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
7971abe55efSEd Tanous                const std::vector<std::string>& params) override
7981abe55efSEd Tanous     {
7990f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc";
8000f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager";
8010f74e643SEd Tanous         res.jsonValue["@odata.context"] =
8020f74e643SEd Tanous             "/redfish/v1/$metadata#Manager.Manager";
8030f74e643SEd Tanous         res.jsonValue["Id"] = "bmc";
8040f74e643SEd Tanous         res.jsonValue["Name"] = "OpenBmc Manager";
8050f74e643SEd Tanous         res.jsonValue["Description"] = "Baseboard Management Controller";
8060f74e643SEd Tanous         res.jsonValue["PowerState"] = "On";
8070f74e643SEd Tanous         res.jsonValue["ManagerType"] = "BMC";
8087517658eSEd Tanous         res.jsonValue["UUID"] = uuid;
8090f74e643SEd Tanous         res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
8100f74e643SEd Tanous 
8110f74e643SEd Tanous         res.jsonValue["LogServices"] = {
8120f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
8130f74e643SEd Tanous 
8140f74e643SEd Tanous         res.jsonValue["NetworkProtocol"] = {
8150f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
8160f74e643SEd Tanous 
8170f74e643SEd Tanous         res.jsonValue["EthernetInterfaces"] = {
8180f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
8190f74e643SEd Tanous         // default oem data
8200f74e643SEd Tanous         nlohmann::json& oem = res.jsonValue["Oem"];
8210f74e643SEd Tanous         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
8220f74e643SEd Tanous         oem["@odata.type"] = "#OemManager.Oem";
8230f74e643SEd Tanous         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
8240f74e643SEd Tanous         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
8250f74e643SEd Tanous         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
8260f74e643SEd Tanous         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
8270f74e643SEd Tanous         oemOpenbmc["@odata.context"] =
8280f74e643SEd Tanous             "/redfish/v1/$metadata#OemManager.OpenBmc";
8290f74e643SEd Tanous 
830ed5befbdSJennifer Lee         // Update Actions object.
8310f74e643SEd Tanous         nlohmann::json& manager_reset =
8320f74e643SEd Tanous             res.jsonValue["Actions"]["#Manager.Reset"];
833ed5befbdSJennifer Lee         manager_reset["target"] =
834ed5befbdSJennifer Lee             "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
835ed5befbdSJennifer Lee         manager_reset["ResetType@Redfish.AllowableValues"] = {
836ed5befbdSJennifer Lee             "GracefulRestart"};
837ca537928SJennifer Lee 
8380f74e643SEd Tanous         res.jsonValue["DateTime"] = getDateTime();
839ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
8405b4aa86bSJames Feist 
841ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
842ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
8435b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
844ca537928SJennifer Lee                 if (ec)
845ca537928SJennifer Lee                 {
846ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
847f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
848ca537928SJennifer Lee                     return;
849ca537928SJennifer Lee                 }
850ca537928SJennifer Lee 
851ca537928SJennifer Lee                 for (auto& objpath : resp)
852ca537928SJennifer Lee                 {
853ca537928SJennifer Lee                     for (auto& interface : objpath.second)
854ca537928SJennifer Lee                     {
855ca537928SJennifer Lee                         // If interface is xyz.openbmc_project.Software.Version,
856ca537928SJennifer Lee                         // this is what we're looking for.
857ca537928SJennifer Lee                         if (interface.first ==
858ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
859ca537928SJennifer Lee                         {
860ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
861ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
862ca537928SJennifer Lee                             for (auto& property : interface.second)
863ca537928SJennifer Lee                             {
864ca537928SJennifer Lee                                 if (property.first == "Version")
865ca537928SJennifer Lee                                 {
866ca537928SJennifer Lee                                     const std::string* value =
8671b6b96c5SEd Tanous                                         sdbusplus::message::variant_ns::get_if<
8681b6b96c5SEd Tanous                                             std::string>(&property.second);
869ca537928SJennifer Lee                                     if (value == nullptr)
870ca537928SJennifer Lee                                     {
871ca537928SJennifer Lee                                         continue;
872ca537928SJennifer Lee                                     }
873ca537928SJennifer Lee                                     asyncResp->res
874ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
875ca537928SJennifer Lee                                 }
876ca537928SJennifer Lee                             }
877ca537928SJennifer Lee                         }
878ca537928SJennifer Lee                     }
879ca537928SJennifer Lee                 }
880ca537928SJennifer Lee             },
881ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
882ca537928SJennifer Lee             "/xyz/openbmc_project/software",
883ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8845b4aa86bSJames Feist         getPidValues(asyncResp);
8855b4aa86bSJames Feist     }
88683ff9ab6SJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response,
88783ff9ab6SJames Feist                       const nlohmann::json& data)
88883ff9ab6SJames Feist     {
88983ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
89083ff9ab6SJames Feist         // interface gets more traction
89183ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
89283ff9ab6SJames Feist             [response,
89383ff9ab6SJames Feist              data](const boost::system::error_code ec,
89483ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
89583ff9ab6SJames Feist                 if (ec)
89683ff9ab6SJames Feist                 {
89783ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
89835a62c7cSJason M. Bills                     messages::internalError(response->res);
89983ff9ab6SJames Feist                     return;
90083ff9ab6SJames Feist                 }
90183ff9ab6SJames Feist                 for (const auto& type : data.items())
90283ff9ab6SJames Feist                 {
90383ff9ab6SJames Feist                     if (!type.value().is_object())
90483ff9ab6SJames Feist                     {
90583ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << type.key();
90635a62c7cSJason M. Bills                         messages::propertyValueFormatError(
90735a62c7cSJason M. Bills                             response->res, type.value(), type.key());
90883ff9ab6SJames Feist                         return;
90983ff9ab6SJames Feist                     }
91083ff9ab6SJames Feist                     for (const auto& record : type.value().items())
91183ff9ab6SJames Feist                     {
91283ff9ab6SJames Feist                         const std::string& name = record.key();
91383ff9ab6SJames Feist                         auto pathItr =
91483ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
91583ff9ab6SJames Feist                                          [&name](const auto& obj) {
91683ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
91783ff9ab6SJames Feist                                                  obj.first.str, name);
91883ff9ab6SJames Feist                                          });
91983ff9ab6SJames Feist                         boost::container::flat_map<
92083ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
92183ff9ab6SJames Feist                             output;
92283ff9ab6SJames Feist 
92383ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
92483ff9ab6SJames Feist 
92583ff9ab6SJames Feist                         // determines if we're patching entity-manager or
92683ff9ab6SJames Feist                         // creating a new object
92783ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
92883ff9ab6SJames Feist                         if (type.key() == "PidControllers" ||
92983ff9ab6SJames Feist                             type.key() == "FanControllers")
93083ff9ab6SJames Feist                         {
93183ff9ab6SJames Feist                             if (!createNewObject &&
93283ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
93383ff9ab6SJames Feist                                     pathItr->second.end())
93483ff9ab6SJames Feist                             {
93583ff9ab6SJames Feist                                 createNewObject = true;
93683ff9ab6SJames Feist                             }
93783ff9ab6SJames Feist                         }
93883ff9ab6SJames Feist                         else if (!createNewObject &&
93983ff9ab6SJames Feist                                  pathItr->second.find(
94083ff9ab6SJames Feist                                      pidZoneConfigurationIface) ==
94183ff9ab6SJames Feist                                      pathItr->second.end())
94283ff9ab6SJames Feist                         {
94383ff9ab6SJames Feist                             createNewObject = true;
94483ff9ab6SJames Feist                         }
94583ff9ab6SJames Feist                         output["Name"] =
94683ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
94783ff9ab6SJames Feist 
94883ff9ab6SJames Feist                         std::string chassis;
94983ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
95083ff9ab6SJames Feist                             response, type.key(), record.value(),
95183ff9ab6SJames Feist                             pathItr->first.str, managedObj, createNewObject,
95283ff9ab6SJames Feist                             output, chassis);
95383ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
95483ff9ab6SJames Feist                         {
95583ff9ab6SJames Feist                             return;
95683ff9ab6SJames Feist                         }
95783ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
95883ff9ab6SJames Feist                         {
95983ff9ab6SJames Feist                             continue;
96083ff9ab6SJames Feist                         }
96183ff9ab6SJames Feist 
96283ff9ab6SJames Feist                         if (!createNewObject)
96383ff9ab6SJames Feist                         {
96483ff9ab6SJames Feist                             for (const auto& property : output)
96583ff9ab6SJames Feist                             {
96683ff9ab6SJames Feist                                 const char* iface =
96783ff9ab6SJames Feist                                     type.key() == "FanZones"
96883ff9ab6SJames Feist                                         ? pidZoneConfigurationIface
96983ff9ab6SJames Feist                                         : pidConfigurationIface;
97083ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
97183ff9ab6SJames Feist                                     [response,
97283ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
97383ff9ab6SJames Feist                                         const boost::system::error_code ec) {
97483ff9ab6SJames Feist                                         if (ec)
97583ff9ab6SJames Feist                                         {
97683ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
97783ff9ab6SJames Feist                                                 << "Error patching "
97883ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
97935a62c7cSJason M. Bills                                             messages::internalError(
98035a62c7cSJason M. Bills                                                 response->res);
98183ff9ab6SJames Feist                                         }
98283ff9ab6SJames Feist                                     },
98383ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
98483ff9ab6SJames Feist                                     pathItr->first.str,
98583ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
98683ff9ab6SJames Feist                                     std::string(iface), property.first,
98783ff9ab6SJames Feist                                     property.second);
98883ff9ab6SJames Feist                             }
98983ff9ab6SJames Feist                         }
99083ff9ab6SJames Feist                         else
99183ff9ab6SJames Feist                         {
99283ff9ab6SJames Feist                             if (chassis.empty())
99383ff9ab6SJames Feist                             {
99483ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
99583ff9ab6SJames Feist                                     << "Failed to get chassis from config";
99635a62c7cSJason M. Bills                                 messages::invalidObject(response->res, name);
99783ff9ab6SJames Feist                                 return;
99883ff9ab6SJames Feist                             }
99983ff9ab6SJames Feist 
100083ff9ab6SJames Feist                             bool foundChassis = false;
100183ff9ab6SJames Feist                             for (const auto& obj : managedObj)
100283ff9ab6SJames Feist                             {
100383ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
100483ff9ab6SJames Feist                                                                 chassis))
100583ff9ab6SJames Feist                                 {
100683ff9ab6SJames Feist                                     chassis = obj.first.str;
100783ff9ab6SJames Feist                                     foundChassis = true;
100883ff9ab6SJames Feist                                     break;
100983ff9ab6SJames Feist                                 }
101083ff9ab6SJames Feist                             }
101183ff9ab6SJames Feist                             if (!foundChassis)
101283ff9ab6SJames Feist                             {
101383ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
101483ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
101583ff9ab6SJames Feist                                 messages::resourceMissingAtURI(
101635a62c7cSJason M. Bills                                     response->res,
101735a62c7cSJason M. Bills                                     "/redfish/v1/Chassis/" + chassis);
101883ff9ab6SJames Feist                                 return;
101983ff9ab6SJames Feist                             }
102083ff9ab6SJames Feist 
102183ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
102283ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
102383ff9ab6SJames Feist                                     if (ec)
102483ff9ab6SJames Feist                                     {
102583ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
102683ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
102735a62c7cSJason M. Bills                                         messages::internalError(response->res);
102883ff9ab6SJames Feist                                     }
102983ff9ab6SJames Feist                                 },
103083ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
103183ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
103283ff9ab6SJames Feist                                 output);
103383ff9ab6SJames Feist                         }
103483ff9ab6SJames Feist                     }
103583ff9ab6SJames Feist                 }
103683ff9ab6SJames Feist             },
103783ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
103883ff9ab6SJames Feist             "GetManagedObjects");
103983ff9ab6SJames Feist     }
10405b4aa86bSJames Feist 
10415b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
10425b4aa86bSJames Feist                  const std::vector<std::string>& params) override
10435b4aa86bSJames Feist     {
10440627a2c7SEd Tanous         std::optional<nlohmann::json> oem;
10450627a2c7SEd Tanous 
10460627a2c7SEd Tanous         if (!json_util::readJson(req, res, "Oem", oem))
104783ff9ab6SJames Feist         {
104883ff9ab6SJames Feist             return;
104983ff9ab6SJames Feist         }
10500627a2c7SEd Tanous 
105183ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
10520627a2c7SEd Tanous 
10530627a2c7SEd Tanous         if (oem)
105483ff9ab6SJames Feist         {
10550627a2c7SEd Tanous             for (const auto& oemLevel : oem->items())
105683ff9ab6SJames Feist             {
105783ff9ab6SJames Feist                 if (oemLevel.key() == "OpenBmc")
105883ff9ab6SJames Feist                 {
105983ff9ab6SJames Feist                     if (!oemLevel.value().is_object())
106083ff9ab6SJames Feist                     {
106183ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
106235a62c7cSJason M. Bills                         messages::propertyValueFormatError(
10630627a2c7SEd Tanous                             response->res, "Oem", "OemManager.OpenBmc");
106483ff9ab6SJames Feist                         return;
106583ff9ab6SJames Feist                     }
106683ff9ab6SJames Feist                     for (const auto& typeLevel : oemLevel.value().items())
106783ff9ab6SJames Feist                     {
106883ff9ab6SJames Feist 
106983ff9ab6SJames Feist                         if (typeLevel.key() == "Fan")
107083ff9ab6SJames Feist                         {
107183ff9ab6SJames Feist                             if (!typeLevel.value().is_object())
107283ff9ab6SJames Feist                             {
107383ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR << "Bad Patch "
107483ff9ab6SJames Feist                                                  << typeLevel.key();
107583ff9ab6SJames Feist                                 messages::propertyValueFormatError(
107635a62c7cSJason M. Bills                                     response->res, typeLevel.value().dump(),
107735a62c7cSJason M. Bills                                     typeLevel.key());
107883ff9ab6SJames Feist                                 return;
107983ff9ab6SJames Feist                             }
108083ff9ab6SJames Feist                             setPidValues(response,
108183ff9ab6SJames Feist                                          std::move(typeLevel.value()));
108283ff9ab6SJames Feist                         }
108383ff9ab6SJames Feist                         else
108483ff9ab6SJames Feist                         {
108583ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key();
108635a62c7cSJason M. Bills                             messages::propertyUnknown(response->res,
108735a62c7cSJason M. Bills                                                       typeLevel.key());
108883ff9ab6SJames Feist                             return;
108983ff9ab6SJames Feist                         }
109083ff9ab6SJames Feist                     }
109183ff9ab6SJames Feist                 }
109283ff9ab6SJames Feist                 else
109383ff9ab6SJames Feist                 {
109483ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
109535a62c7cSJason M. Bills                     messages::propertyUnknown(response->res, oemLevel.key());
109683ff9ab6SJames Feist                     return;
109783ff9ab6SJames Feist                 }
109883ff9ab6SJames Feist             }
109983ff9ab6SJames Feist         }
11009c310685SBorawski.Lukasz     }
11019c310685SBorawski.Lukasz 
11021abe55efSEd Tanous     std::string getDateTime() const
11031abe55efSEd Tanous     {
11049c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
11059c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
11069c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
11079c310685SBorawski.Lukasz 
11089c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
11091abe55efSEd Tanous                           std::localtime(&time)))
11101abe55efSEd Tanous         {
11119c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
11129c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
11139c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
11149c310685SBorawski.Lukasz         }
11159c310685SBorawski.Lukasz 
11169c310685SBorawski.Lukasz         return redfishDateTime;
11179c310685SBorawski.Lukasz     }
11180f74e643SEd Tanous 
11190f74e643SEd Tanous     std::string uuid;
11209c310685SBorawski.Lukasz };
11219c310685SBorawski.Lukasz 
11221abe55efSEd Tanous class ManagerCollection : public Node
11231abe55efSEd Tanous {
11249c310685SBorawski.Lukasz   public:
11251abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
11261abe55efSEd Tanous     {
1127a434f2bdSEd Tanous         entityPrivileges = {
1128a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
1129e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1130e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1131e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1132e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1133e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
11349c310685SBorawski.Lukasz     }
11359c310685SBorawski.Lukasz 
11369c310685SBorawski.Lukasz   private:
113755c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
11381abe55efSEd Tanous                const std::vector<std::string>& params) override
11391abe55efSEd Tanous     {
114083ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
114183ff9ab6SJames Feist         // because it has a duplicate entry for members
114255c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
114355c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
114455c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
114555c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
114655c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
114755c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
114855c7b7a2SEd Tanous         res.jsonValue["Members"] = {
11495b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
11509c310685SBorawski.Lukasz         res.end();
11519c310685SBorawski.Lukasz     }
11529c310685SBorawski.Lukasz };
11539c310685SBorawski.Lukasz } // namespace redfish
1154