xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision 5f2caaef9fec67f3b4da92b7eddcf125b6987f46)
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";
115b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface =
116b7a08d04SJames 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 
149b7a08d04SJames Feist             nlohmann::json& stepwise = configRoot["StepwiseControllers"];
150b7a08d04SJames Feist             stepwise["@odata.type"] = "#OemManager.StepwiseControllers";
151b7a08d04SJames Feist             stepwise["@odata.context"] =
152b7a08d04SJames Feist                 "/redfish/v1/$metadata#OemManager.StepwiseControllers";
153b7a08d04SJames Feist             stepwise["@odata.id"] =
154b7a08d04SJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers";
155b7a08d04SJames 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 &&
174b7a08d04SJames Feist                         intfPair.first != pidZoneConfigurationIface &&
175b7a08d04SJames 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";
192b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
1935b4aa86bSJames Feist                         return;
1945b4aa86bSJames Feist                     }
1955b4aa86bSJames Feist 
1965b4aa86bSJames Feist                     std::string name = *namePtr;
1975b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
198b7a08d04SJames 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";
216b7a08d04SJames Feist                         config = &zone;
2175b4aa86bSJames Feist                     }
2185b4aa86bSJames Feist 
219b7a08d04SJames Feist                     else if (intfPair.first == stepwiseConfigurationIface)
2205b4aa86bSJames Feist                     {
221b7a08d04SJames Feist                         nlohmann::json& controller = stepwise[name];
222b7a08d04SJames Feist                         config = &controller;
2235b4aa86bSJames Feist 
224b7a08d04SJames Feist                         controller["@odata.id"] =
225b7a08d04SJames Feist                             "/redfish/v1/Managers/bmc#/Oem/"
226b7a08d04SJames Feist                             "OpenBmc/Fan/StepwiseControllers/" +
227b7a08d04SJames Feist                             std::string(name);
228b7a08d04SJames Feist                         controller["@odata.type"] =
229b7a08d04SJames Feist                             "#OemManager.StepwiseController";
230b7a08d04SJames Feist 
231b7a08d04SJames Feist                         controller["@odata.context"] =
232b7a08d04SJames Feist                             "/redfish/v1/"
233b7a08d04SJames Feist                             "$metadata#OemManager.StepwiseController";
2345b4aa86bSJames Feist                     }
2355b4aa86bSJames Feist 
2365b4aa86bSJames Feist                     // pid and fans are off the same configuration
237b7a08d04SJames 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                         {
243b7a08d04SJames 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];
255b7a08d04SJames 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                         }
281b7a08d04SJames Feist                     }
282b7a08d04SJames Feist                     else
283b7a08d04SJames Feist                     {
284b7a08d04SJames Feist                         BMCWEB_LOG_ERROR << "Unexpected configuration";
285b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
286b7a08d04SJames Feist                         return;
287b7a08d04SJames Feist                     }
288b7a08d04SJames Feist 
289b7a08d04SJames Feist                     // used for making maps out of 2 vectors
290b7a08d04SJames Feist                     const std::vector<double>* keys = nullptr;
291b7a08d04SJames Feist                     const std::vector<double>* values = nullptr;
292b7a08d04SJames Feist 
293b7a08d04SJames Feist                     for (const auto& propertyPair : intfPair.second)
294b7a08d04SJames Feist                     {
295b7a08d04SJames Feist                         if (propertyPair.first == "Type" ||
296b7a08d04SJames Feist                             propertyPair.first == "Class" ||
297b7a08d04SJames Feist                             propertyPair.first == "Name")
298b7a08d04SJames Feist                         {
299b7a08d04SJames Feist                             continue;
300b7a08d04SJames Feist                         }
301b7a08d04SJames Feist 
302b7a08d04SJames Feist                         // zones
303b7a08d04SJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
304b7a08d04SJames Feist                         {
305b7a08d04SJames Feist                             const double* ptr =
306b7a08d04SJames Feist                                 sdbusplus::message::variant_ns::get_if<double>(
307b7a08d04SJames Feist                                     &propertyPair.second);
308b7a08d04SJames Feist                             if (ptr == nullptr)
309b7a08d04SJames Feist                             {
310b7a08d04SJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
311b7a08d04SJames Feist                                                  << propertyPair.first;
312b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
313b7a08d04SJames Feist                                 return;
314b7a08d04SJames Feist                             }
315b7a08d04SJames Feist                             (*config)[propertyPair.first] = *ptr;
316b7a08d04SJames Feist                         }
317b7a08d04SJames Feist 
318b7a08d04SJames Feist                         if (intfPair.first == stepwiseConfigurationIface)
319b7a08d04SJames Feist                         {
320b7a08d04SJames Feist                             if (propertyPair.first == "Reading" ||
321b7a08d04SJames Feist                                 propertyPair.first == "Output")
322b7a08d04SJames Feist                             {
323b7a08d04SJames Feist                                 const std::vector<double>* ptr =
324b7a08d04SJames Feist                                     sdbusplus::message::variant_ns::get_if<
325b7a08d04SJames Feist                                         std::vector<double>>(
326b7a08d04SJames Feist                                         &propertyPair.second);
327b7a08d04SJames Feist 
328b7a08d04SJames Feist                                 if (ptr == nullptr)
329b7a08d04SJames Feist                                 {
330b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
331b7a08d04SJames Feist                                                      << propertyPair.first;
332b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
333b7a08d04SJames Feist                                     return;
334b7a08d04SJames Feist                                 }
335b7a08d04SJames Feist 
336b7a08d04SJames Feist                                 if (propertyPair.first == "Reading")
337b7a08d04SJames Feist                                 {
338b7a08d04SJames Feist                                     keys = ptr;
339b7a08d04SJames Feist                                 }
340b7a08d04SJames Feist                                 else
341b7a08d04SJames Feist                                 {
342b7a08d04SJames Feist                                     values = ptr;
343b7a08d04SJames Feist                                 }
344b7a08d04SJames Feist                                 if (keys && values)
345b7a08d04SJames Feist                                 {
346b7a08d04SJames Feist                                     if (keys->size() != values->size())
347b7a08d04SJames Feist                                     {
348b7a08d04SJames Feist                                         BMCWEB_LOG_ERROR
349b7a08d04SJames Feist                                             << "Reading and Output size don't "
350b7a08d04SJames Feist                                                "match ";
351b7a08d04SJames Feist                                         messages::internalError(asyncResp->res);
352b7a08d04SJames Feist                                         return;
353b7a08d04SJames Feist                                     }
354b7a08d04SJames Feist                                     nlohmann::json& steps = (*config)["Steps"];
355b7a08d04SJames Feist                                     steps = nlohmann::json::array();
356b7a08d04SJames Feist                                     for (size_t ii = 0; ii < keys->size(); ii++)
357b7a08d04SJames Feist                                     {
358b7a08d04SJames Feist                                         steps.push_back(
359b7a08d04SJames Feist                                             {{"Target", (*keys)[ii]},
360b7a08d04SJames Feist                                              {"Output", (*values)[ii]}});
361b7a08d04SJames Feist                                     }
362b7a08d04SJames Feist                                 }
363b7a08d04SJames Feist                             }
364b7a08d04SJames Feist                             if (propertyPair.first == "NegativeHysteresis" ||
365b7a08d04SJames Feist                                 propertyPair.first == "PositiveHysteresis")
366b7a08d04SJames Feist                             {
367b7a08d04SJames Feist                                 const double* ptr =
368b7a08d04SJames Feist                                     sdbusplus::message::variant_ns::get_if<
369b7a08d04SJames Feist                                         double>(&propertyPair.second);
370b7a08d04SJames Feist                                 if (ptr == nullptr)
371b7a08d04SJames Feist                                 {
372b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
373b7a08d04SJames Feist                                                      << propertyPair.first;
374b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
375b7a08d04SJames Feist                                     return;
376b7a08d04SJames Feist                                 }
377b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
378b7a08d04SJames Feist                             }
379b7a08d04SJames Feist                         }
380b7a08d04SJames Feist 
381b7a08d04SJames Feist                         // pid and fans are off the same configuration
382b7a08d04SJames Feist                         if (intfPair.first == pidConfigurationIface ||
383b7a08d04SJames Feist                             intfPair.first == stepwiseConfigurationIface)
384b7a08d04SJames 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                                 }
400b7a08d04SJames 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                             {
422b7a08d04SJames 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                                 }
459b7a08d04SJames 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 
476*5f2caaefSJames Feist static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response,
477*5f2caaefSJames Feist                                 std::vector<nlohmann::json>& config,
478*5f2caaefSJames Feist                                 std::vector<std::string>& zones)
479*5f2caaefSJames Feist {
480*5f2caaefSJames Feist 
481*5f2caaefSJames Feist     for (auto& odata : config)
482*5f2caaefSJames Feist     {
483*5f2caaefSJames Feist         std::string path;
484*5f2caaefSJames Feist         if (!redfish::json_util::readJson(odata, response->res, "@odata.id",
485*5f2caaefSJames Feist                                           path))
486*5f2caaefSJames Feist         {
487*5f2caaefSJames Feist             return false;
488*5f2caaefSJames Feist         }
489*5f2caaefSJames Feist         std::string input;
490*5f2caaefSJames Feist         if (!dbus::utility::getNthStringFromPath(path, 4, input))
491*5f2caaefSJames Feist         {
492*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Got invalid path " << path;
493*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Illegal Type Zones";
494*5f2caaefSJames Feist             messages::propertyValueFormatError(response->res, odata.dump(),
495*5f2caaefSJames Feist                                                "Zones");
496*5f2caaefSJames Feist             return false;
497*5f2caaefSJames Feist         }
498*5f2caaefSJames Feist         boost::replace_all(input, "_", " ");
499*5f2caaefSJames Feist         zones.emplace_back(std::move(input));
500*5f2caaefSJames Feist     }
501*5f2caaefSJames Feist     return true;
502*5f2caaefSJames Feist }
503*5f2caaefSJames Feist 
50483ff9ab6SJames Feist static CreatePIDRet createPidInterface(
50583ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
506*5f2caaefSJames Feist     nlohmann::json&& record, const std::string& path,
50783ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
50883ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
50983ff9ab6SJames Feist         output,
51083ff9ab6SJames Feist     std::string& chassis)
51183ff9ab6SJames Feist {
51283ff9ab6SJames Feist 
513*5f2caaefSJames Feist     // common deleter
514*5f2caaefSJames Feist     if (record == nullptr)
515*5f2caaefSJames Feist     {
516*5f2caaefSJames Feist         std::string iface;
517*5f2caaefSJames Feist         if (type == "PidControllers" || type == "FanControllers")
518*5f2caaefSJames Feist         {
519*5f2caaefSJames Feist             iface = pidConfigurationIface;
520*5f2caaefSJames Feist         }
521*5f2caaefSJames Feist         else if (type == "FanZones")
522*5f2caaefSJames Feist         {
523*5f2caaefSJames Feist             iface = pidZoneConfigurationIface;
524*5f2caaefSJames Feist         }
525*5f2caaefSJames Feist         else if (type == "StepwiseControllers")
526*5f2caaefSJames Feist         {
527*5f2caaefSJames Feist             iface = stepwiseConfigurationIface;
528*5f2caaefSJames Feist         }
529*5f2caaefSJames Feist         else
530*5f2caaefSJames Feist         {
531*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type "
532*5f2caaefSJames Feist                              << type;
533*5f2caaefSJames Feist             messages::propertyUnknown(response->res, type);
534*5f2caaefSJames Feist             return CreatePIDRet::fail;
535*5f2caaefSJames Feist         }
536*5f2caaefSJames Feist         // delete interface
537*5f2caaefSJames Feist         crow::connections::systemBus->async_method_call(
538*5f2caaefSJames Feist             [response, path](const boost::system::error_code ec) {
539*5f2caaefSJames Feist                 if (ec)
540*5f2caaefSJames Feist                 {
541*5f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec;
542*5f2caaefSJames Feist                     messages::internalError(response->res);
543*5f2caaefSJames Feist                 }
544*5f2caaefSJames Feist             },
545*5f2caaefSJames Feist             "xyz.openbmc_project.EntityManager", path, iface, "Delete");
546*5f2caaefSJames Feist         return CreatePIDRet::del;
547*5f2caaefSJames Feist     }
548*5f2caaefSJames Feist 
54983ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
55083ff9ab6SJames Feist     {
55183ff9ab6SJames Feist         if (createNewObject)
55283ff9ab6SJames Feist         {
55383ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
55483ff9ab6SJames Feist                                                        : std::string("fan");
55583ff9ab6SJames Feist             output["Type"] = std::string("Pid");
55683ff9ab6SJames Feist         }
557*5f2caaefSJames Feist 
558*5f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> zones;
559*5f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
560*5f2caaefSJames Feist         std::optional<std::vector<std::string>> outputs;
561*5f2caaefSJames Feist         std::map<std::string, std::optional<double>> doubles;
562*5f2caaefSJames Feist         if (!redfish::json_util::readJson(
563*5f2caaefSJames Feist                 record, response->res, "Inputs", inputs, "Outputs", outputs,
564*5f2caaefSJames Feist                 "Zones", zones, "FFGainCoefficient",
565*5f2caaefSJames Feist                 doubles["FFGainCoefficient"], "FFOffCoefficient",
566*5f2caaefSJames Feist                 doubles["FFOffCoefficient"], "ICoefficient",
567*5f2caaefSJames Feist                 doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"],
568*5f2caaefSJames Feist                 "ILimitMin", doubles["ILimitMin"], "OutLimitMax",
569*5f2caaefSJames Feist                 doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"],
570*5f2caaefSJames Feist                 "PCoefficient", doubles["PCoefficient"], "SetPoint",
571*5f2caaefSJames Feist                 doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos",
572*5f2caaefSJames Feist                 doubles["SlewPos"]))
57383ff9ab6SJames Feist         {
574*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
575*5f2caaefSJames Feist                              << record.dump();
576*5f2caaefSJames Feist             return CreatePIDRet::fail;
57783ff9ab6SJames Feist         }
578*5f2caaefSJames Feist         if (zones)
579*5f2caaefSJames Feist         {
580*5f2caaefSJames Feist             std::vector<std::string> zonesStr;
581*5f2caaefSJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStr))
582*5f2caaefSJames Feist             {
583*5f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
584*5f2caaefSJames Feist                 return CreatePIDRet::fail;
585*5f2caaefSJames Feist             }
586*5f2caaefSJames Feist             output["Zones"] = std::move(zonesStr);
587*5f2caaefSJames Feist         }
588*5f2caaefSJames Feist         if (inputs || outputs)
589*5f2caaefSJames Feist         {
590*5f2caaefSJames Feist             std::array<std::optional<std::vector<std::string>>*, 2> containers =
591*5f2caaefSJames Feist                 {&inputs, &outputs};
592*5f2caaefSJames Feist             size_t index = 0;
593*5f2caaefSJames Feist             for (const auto& containerPtr : containers)
594*5f2caaefSJames Feist             {
595*5f2caaefSJames Feist                 std::optional<std::vector<std::string>>& container =
596*5f2caaefSJames Feist                     *containerPtr;
597*5f2caaefSJames Feist                 if (!container)
598*5f2caaefSJames Feist                 {
599*5f2caaefSJames Feist                     index++;
600*5f2caaefSJames Feist                     continue;
60183ff9ab6SJames Feist                 }
60283ff9ab6SJames Feist 
603*5f2caaefSJames Feist                 for (std::string& value : *container)
60483ff9ab6SJames Feist                 {
60583ff9ab6SJames Feist 
60683ff9ab6SJames Feist                     // try to find the sensor in the
60783ff9ab6SJames Feist                     // configuration
60883ff9ab6SJames Feist                     if (chassis.empty())
60983ff9ab6SJames Feist                     {
610*5f2caaefSJames Feist                         std::string escaped =
611*5f2caaefSJames Feist                             boost::replace_all_copy(value, " ", "_");
61283ff9ab6SJames Feist                         std::find_if(
61383ff9ab6SJames Feist                             managedObj.begin(), managedObj.end(),
614*5f2caaefSJames Feist                             [&chassis, &escaped](const auto& obj) {
61583ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
616*5f2caaefSJames Feist                                                                 escaped))
61783ff9ab6SJames Feist                                 {
61883ff9ab6SJames Feist                                     return dbus::utility::getNthStringFromPath(
61983ff9ab6SJames Feist                                         obj.first.str, 5, chassis);
62083ff9ab6SJames Feist                                 }
62183ff9ab6SJames Feist                                 return false;
62283ff9ab6SJames Feist                             });
62383ff9ab6SJames Feist                     }
624*5f2caaefSJames Feist                     boost::replace_all(value, "_", " ");
62583ff9ab6SJames Feist                 }
626*5f2caaefSJames Feist                 std::string key;
627*5f2caaefSJames Feist                 if (index == 0)
628*5f2caaefSJames Feist                 {
629*5f2caaefSJames Feist                     key = "Inputs";
630*5f2caaefSJames Feist                 }
631*5f2caaefSJames Feist                 else
632*5f2caaefSJames Feist                 {
633*5f2caaefSJames Feist                     key = "Outputs";
634*5f2caaefSJames Feist                 }
635*5f2caaefSJames Feist                 output[key] = *container;
636*5f2caaefSJames Feist                 index++;
637*5f2caaefSJames Feist             }
63883ff9ab6SJames Feist         }
63983ff9ab6SJames Feist 
64083ff9ab6SJames Feist         // doubles
641*5f2caaefSJames Feist         for (const auto& pairs : doubles)
64283ff9ab6SJames Feist         {
643*5f2caaefSJames Feist             if (!pairs.second)
64483ff9ab6SJames Feist             {
645*5f2caaefSJames Feist                 continue;
64683ff9ab6SJames Feist             }
647*5f2caaefSJames Feist             BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second;
648*5f2caaefSJames Feist             output[pairs.first] = *(pairs.second);
649*5f2caaefSJames Feist         }
65083ff9ab6SJames Feist     }
65183ff9ab6SJames Feist 
65283ff9ab6SJames Feist     else if (type == "FanZones")
65383ff9ab6SJames Feist     {
65483ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
65583ff9ab6SJames Feist 
656*5f2caaefSJames Feist         std::optional<nlohmann::json> chassisContainer;
657*5f2caaefSJames Feist         std::optional<double> failSafePercent;
658*5f2caaefSJames Feist         std::optional<double> minThermalRpm;
659*5f2caaefSJames Feist         if (!redfish::json_util::readJson(record, response->res, "Chassis",
660*5f2caaefSJames Feist                                           chassisContainer, "FailSafePercent",
661*5f2caaefSJames Feist                                           failSafePercent, "MinThermalRpm",
662*5f2caaefSJames Feist                                           minThermalRpm))
66383ff9ab6SJames Feist         {
664*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
665*5f2caaefSJames Feist                              << record.dump();
66683ff9ab6SJames Feist             return CreatePIDRet::fail;
66783ff9ab6SJames Feist         }
668*5f2caaefSJames Feist 
669*5f2caaefSJames Feist         if (chassisContainer)
67083ff9ab6SJames Feist         {
671*5f2caaefSJames Feist 
672*5f2caaefSJames Feist             std::string chassisId;
673*5f2caaefSJames Feist             if (!redfish::json_util::readJson(*chassisContainer, response->res,
674*5f2caaefSJames Feist                                               "@odata.id", chassisId))
675*5f2caaefSJames Feist             {
676*5f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
677*5f2caaefSJames Feist                                  << chassisContainer->dump();
67883ff9ab6SJames Feist                 return CreatePIDRet::fail;
67983ff9ab6SJames Feist             }
68083ff9ab6SJames Feist 
68183ff9ab6SJames Feist             // /refish/v1/chassis/chassis_name/
682*5f2caaefSJames Feist             if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis))
68383ff9ab6SJames Feist             {
684*5f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Got invalid path " << chassisId;
685*5f2caaefSJames Feist                 messages::invalidObject(response->res, chassisId);
68683ff9ab6SJames Feist                 return CreatePIDRet::fail;
68783ff9ab6SJames Feist             }
68883ff9ab6SJames Feist         }
689*5f2caaefSJames Feist         if (minThermalRpm)
69083ff9ab6SJames Feist         {
691*5f2caaefSJames Feist             output["MinThermalRpm"] = *minThermalRpm;
692*5f2caaefSJames Feist         }
693*5f2caaefSJames Feist         if (failSafePercent)
69483ff9ab6SJames Feist         {
695*5f2caaefSJames Feist             output["FailSafePercent"] = *failSafePercent;
696*5f2caaefSJames Feist         }
697*5f2caaefSJames Feist     }
698*5f2caaefSJames Feist     else if (type == "StepwiseControllers")
699*5f2caaefSJames Feist     {
700*5f2caaefSJames Feist         output["Type"] = std::string("Stepwise");
701*5f2caaefSJames Feist 
702*5f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> zones;
703*5f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> steps;
704*5f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
705*5f2caaefSJames Feist         std::optional<double> positiveHysteresis;
706*5f2caaefSJames Feist         std::optional<double> negativeHysteresis;
707*5f2caaefSJames Feist         if (!redfish::json_util::readJson(
708*5f2caaefSJames Feist                 record, response->res, "Zones", zones, "Steps", steps, "Inputs",
709*5f2caaefSJames Feist                 inputs, "PositiveHysteresis", positiveHysteresis,
710*5f2caaefSJames Feist                 "NegativeHysteresis", negativeHysteresis))
711*5f2caaefSJames Feist         {
712*5f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
713*5f2caaefSJames Feist                              << record.dump();
71483ff9ab6SJames Feist             return CreatePIDRet::fail;
71583ff9ab6SJames Feist         }
716*5f2caaefSJames Feist 
717*5f2caaefSJames Feist         if (zones)
71883ff9ab6SJames Feist         {
719*5f2caaefSJames Feist             std::vector<std::string> zoneStrs;
720*5f2caaefSJames Feist             if (!getZonesFromJsonReq(response, *zones, zoneStrs))
721*5f2caaefSJames Feist             {
722*5f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
72383ff9ab6SJames Feist                 return CreatePIDRet::fail;
72483ff9ab6SJames Feist             }
725*5f2caaefSJames Feist             output["Zones"] = std::move(zoneStrs);
726*5f2caaefSJames Feist         }
727*5f2caaefSJames Feist         if (steps)
728*5f2caaefSJames Feist         {
729*5f2caaefSJames Feist             std::vector<double> readings;
730*5f2caaefSJames Feist             std::vector<double> outputs;
731*5f2caaefSJames Feist             for (auto& step : *steps)
732*5f2caaefSJames Feist             {
733*5f2caaefSJames Feist                 double target;
734*5f2caaefSJames Feist                 double output;
735*5f2caaefSJames Feist 
736*5f2caaefSJames Feist                 if (!redfish::json_util::readJson(step, response->res, "Target",
737*5f2caaefSJames Feist                                                   target, "Output", output))
738*5f2caaefSJames Feist                 {
739*5f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
740*5f2caaefSJames Feist                                      << ", Illegal Property " << record.dump();
741*5f2caaefSJames Feist                     return CreatePIDRet::fail;
742*5f2caaefSJames Feist                 }
743*5f2caaefSJames Feist                 readings.emplace_back(target);
744*5f2caaefSJames Feist                 outputs.emplace_back(output);
745*5f2caaefSJames Feist             }
746*5f2caaefSJames Feist             output["Reading"] = std::move(readings);
747*5f2caaefSJames Feist             output["Output"] = std::move(outputs);
748*5f2caaefSJames Feist         }
749*5f2caaefSJames Feist         if (inputs)
750*5f2caaefSJames Feist         {
751*5f2caaefSJames Feist             for (std::string& value : *inputs)
752*5f2caaefSJames Feist             {
753*5f2caaefSJames Feist                 if (chassis.empty())
754*5f2caaefSJames Feist                 {
755*5f2caaefSJames Feist                     std::string escaped =
756*5f2caaefSJames Feist                         boost::replace_all_copy(value, " ", "_");
757*5f2caaefSJames Feist                     std::find_if(
758*5f2caaefSJames Feist                         managedObj.begin(), managedObj.end(),
759*5f2caaefSJames Feist                         [&chassis, &escaped](const auto& obj) {
760*5f2caaefSJames Feist                             if (boost::algorithm::ends_with(obj.first.str,
761*5f2caaefSJames Feist                                                             escaped))
762*5f2caaefSJames Feist                             {
763*5f2caaefSJames Feist                                 return dbus::utility::getNthStringFromPath(
764*5f2caaefSJames Feist                                     obj.first.str, 5, chassis);
765*5f2caaefSJames Feist                             }
766*5f2caaefSJames Feist                             return false;
767*5f2caaefSJames Feist                         });
768*5f2caaefSJames Feist                 }
769*5f2caaefSJames Feist                 boost::replace_all(value, "_", " ");
770*5f2caaefSJames Feist             }
771*5f2caaefSJames Feist             output["Inputs"] = std::move(*inputs);
772*5f2caaefSJames Feist         }
773*5f2caaefSJames Feist         if (negativeHysteresis)
774*5f2caaefSJames Feist         {
775*5f2caaefSJames Feist             output["NegativeHysteresis"] = *negativeHysteresis;
776*5f2caaefSJames Feist         }
777*5f2caaefSJames Feist         if (positiveHysteresis)
778*5f2caaefSJames Feist         {
779*5f2caaefSJames Feist             output["PositiveHysteresis"] = *positiveHysteresis;
78083ff9ab6SJames Feist         }
78183ff9ab6SJames Feist     }
78283ff9ab6SJames Feist     else
78383ff9ab6SJames Feist     {
784*5f2caaefSJames Feist         BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type;
78535a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
78683ff9ab6SJames Feist         return CreatePIDRet::fail;
78783ff9ab6SJames Feist     }
78883ff9ab6SJames Feist     return CreatePIDRet::patch;
78983ff9ab6SJames Feist }
79083ff9ab6SJames Feist 
7911abe55efSEd Tanous class Manager : public Node
7921abe55efSEd Tanous {
7939c310685SBorawski.Lukasz   public:
7945b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
7951abe55efSEd Tanous     {
7960f74e643SEd Tanous         uuid = app.template getMiddleware<crow::persistent_data::Middleware>()
79755c7b7a2SEd Tanous                    .systemUuid;
798a434f2bdSEd Tanous         entityPrivileges = {
799a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
800e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
801e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
802e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
803e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
804e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
8059c310685SBorawski.Lukasz     }
8069c310685SBorawski.Lukasz 
8079c310685SBorawski.Lukasz   private:
8085b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
8095b4aa86bSJames Feist     {
8105b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
8115b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
8125b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
8135b4aa86bSJames Feist                 if (ec)
8145b4aa86bSJames Feist                 {
8155b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
816f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8175b4aa86bSJames Feist                     return;
8185b4aa86bSJames Feist                 }
8195b4aa86bSJames Feist 
8205b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
8215b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
8225b4aa86bSJames Feist                     objectMgrPaths;
8236bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
8245b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
8255b4aa86bSJames Feist                 {
8265b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
8275b4aa86bSJames Feist                     {
8286bce33bcSJames Feist                         auto findConnection =
8296bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
8306bce33bcSJames Feist                         if (findConnection != calledConnections.end())
8316bce33bcSJames Feist                         {
8326bce33bcSJames Feist                             break;
8336bce33bcSJames Feist                         }
8345b4aa86bSJames Feist                         for (const std::string& interface :
8355b4aa86bSJames Feist                              connectionGroup.second)
8365b4aa86bSJames Feist                         {
8375b4aa86bSJames Feist                             if (interface == objectManagerIface)
8385b4aa86bSJames Feist                             {
8395b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
8405b4aa86bSJames Feist                                     pathGroup.first;
8415b4aa86bSJames Feist                             }
8425b4aa86bSJames Feist                             // this list is alphabetical, so we
8435b4aa86bSJames Feist                             // should have found the objMgr by now
8445b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
845b7a08d04SJames Feist                                 interface == pidZoneConfigurationIface ||
846b7a08d04SJames Feist                                 interface == stepwiseConfigurationIface)
8475b4aa86bSJames Feist                             {
8485b4aa86bSJames Feist                                 auto findObjMgr =
8495b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
8505b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
8515b4aa86bSJames Feist                                 {
8525b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
8535b4aa86bSJames Feist                                                      << "Has no Object Manager";
8545b4aa86bSJames Feist                                     continue;
8555b4aa86bSJames Feist                                 }
8566bce33bcSJames Feist 
8576bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
8586bce33bcSJames Feist 
8595b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
8605b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
8615b4aa86bSJames Feist                                 break;
8625b4aa86bSJames Feist                             }
8635b4aa86bSJames Feist                         }
8645b4aa86bSJames Feist                     }
8655b4aa86bSJames Feist                 }
8665b4aa86bSJames Feist             },
8675b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
8685b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
8695b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
870b7a08d04SJames Feist             std::array<const char*, 4>{
871b7a08d04SJames Feist                 pidConfigurationIface, pidZoneConfigurationIface,
872b7a08d04SJames Feist                 objectManagerIface, stepwiseConfigurationIface});
8735b4aa86bSJames Feist     }
8745b4aa86bSJames Feist 
87555c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
8761abe55efSEd Tanous                const std::vector<std::string>& params) override
8771abe55efSEd Tanous     {
8780f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc";
8790f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager";
8800f74e643SEd Tanous         res.jsonValue["@odata.context"] =
8810f74e643SEd Tanous             "/redfish/v1/$metadata#Manager.Manager";
8820f74e643SEd Tanous         res.jsonValue["Id"] = "bmc";
8830f74e643SEd Tanous         res.jsonValue["Name"] = "OpenBmc Manager";
8840f74e643SEd Tanous         res.jsonValue["Description"] = "Baseboard Management Controller";
8850f74e643SEd Tanous         res.jsonValue["PowerState"] = "On";
8860f74e643SEd Tanous         res.jsonValue["ManagerType"] = "BMC";
8877517658eSEd Tanous         res.jsonValue["UUID"] = uuid;
8880f74e643SEd Tanous         res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
8890f74e643SEd Tanous 
8900f74e643SEd Tanous         res.jsonValue["LogServices"] = {
8910f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
8920f74e643SEd Tanous 
8930f74e643SEd Tanous         res.jsonValue["NetworkProtocol"] = {
8940f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
8950f74e643SEd Tanous 
8960f74e643SEd Tanous         res.jsonValue["EthernetInterfaces"] = {
8970f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
8980f74e643SEd Tanous         // default oem data
8990f74e643SEd Tanous         nlohmann::json& oem = res.jsonValue["Oem"];
9000f74e643SEd Tanous         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
9010f74e643SEd Tanous         oem["@odata.type"] = "#OemManager.Oem";
9020f74e643SEd Tanous         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
9030f74e643SEd Tanous         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
9040f74e643SEd Tanous         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
9050f74e643SEd Tanous         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
9060f74e643SEd Tanous         oemOpenbmc["@odata.context"] =
9070f74e643SEd Tanous             "/redfish/v1/$metadata#OemManager.OpenBmc";
9080f74e643SEd Tanous 
909ed5befbdSJennifer Lee         // Update Actions object.
9100f74e643SEd Tanous         nlohmann::json& manager_reset =
9110f74e643SEd Tanous             res.jsonValue["Actions"]["#Manager.Reset"];
912ed5befbdSJennifer Lee         manager_reset["target"] =
913ed5befbdSJennifer Lee             "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
914ed5befbdSJennifer Lee         manager_reset["ResetType@Redfish.AllowableValues"] = {
915ed5befbdSJennifer Lee             "GracefulRestart"};
916ca537928SJennifer Lee 
9170f74e643SEd Tanous         res.jsonValue["DateTime"] = getDateTime();
918ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
9195b4aa86bSJames Feist 
920ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
921ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
9225b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
923ca537928SJennifer Lee                 if (ec)
924ca537928SJennifer Lee                 {
925ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
926f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
927ca537928SJennifer Lee                     return;
928ca537928SJennifer Lee                 }
929ca537928SJennifer Lee 
930ca537928SJennifer Lee                 for (auto& objpath : resp)
931ca537928SJennifer Lee                 {
932ca537928SJennifer Lee                     for (auto& interface : objpath.second)
933ca537928SJennifer Lee                     {
934*5f2caaefSJames Feist                         // If interface is
935*5f2caaefSJames Feist                         // xyz.openbmc_project.Software.Version, this is
936*5f2caaefSJames Feist                         // what we're looking for.
937ca537928SJennifer Lee                         if (interface.first ==
938ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
939ca537928SJennifer Lee                         {
940ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
941ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
942ca537928SJennifer Lee                             for (auto& property : interface.second)
943ca537928SJennifer Lee                             {
944ca537928SJennifer Lee                                 if (property.first == "Version")
945ca537928SJennifer Lee                                 {
946ca537928SJennifer Lee                                     const std::string* value =
9471b6b96c5SEd Tanous                                         sdbusplus::message::variant_ns::get_if<
9481b6b96c5SEd Tanous                                             std::string>(&property.second);
949ca537928SJennifer Lee                                     if (value == nullptr)
950ca537928SJennifer Lee                                     {
951ca537928SJennifer Lee                                         continue;
952ca537928SJennifer Lee                                     }
953ca537928SJennifer Lee                                     asyncResp->res
954ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
955ca537928SJennifer Lee                                 }
956ca537928SJennifer Lee                             }
957ca537928SJennifer Lee                         }
958ca537928SJennifer Lee                     }
959ca537928SJennifer Lee                 }
960ca537928SJennifer Lee             },
961ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
962ca537928SJennifer Lee             "/xyz/openbmc_project/software",
963ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9645b4aa86bSJames Feist         getPidValues(asyncResp);
9655b4aa86bSJames Feist     }
966*5f2caaefSJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data)
96783ff9ab6SJames Feist     {
968*5f2caaefSJames Feist 
96983ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
97083ff9ab6SJames Feist         // interface gets more traction
97183ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
97283ff9ab6SJames Feist             [response,
97383ff9ab6SJames Feist              data](const boost::system::error_code ec,
97483ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
97583ff9ab6SJames Feist                 if (ec)
97683ff9ab6SJames Feist                 {
97783ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
97835a62c7cSJason M. Bills                     messages::internalError(response->res);
97983ff9ab6SJames Feist                     return;
98083ff9ab6SJames Feist                 }
981*5f2caaefSJames Feist 
982*5f2caaefSJames Feist                 // todo(james) mutable doesn't work with asio bindings
983*5f2caaefSJames Feist                 nlohmann::json jsonData = data;
984*5f2caaefSJames Feist 
985*5f2caaefSJames Feist                 std::optional<nlohmann::json> pidControllers;
986*5f2caaefSJames Feist                 std::optional<nlohmann::json> fanControllers;
987*5f2caaefSJames Feist                 std::optional<nlohmann::json> fanZones;
988*5f2caaefSJames Feist                 std::optional<nlohmann::json> stepwiseControllers;
989*5f2caaefSJames Feist                 if (!redfish::json_util::readJson(
990*5f2caaefSJames Feist                         jsonData, response->res, "PidControllers",
991*5f2caaefSJames Feist                         pidControllers, "FanControllers", fanControllers,
992*5f2caaefSJames Feist                         "FanZones", fanZones, "StepwiseControllers",
993*5f2caaefSJames Feist                         stepwiseControllers))
99483ff9ab6SJames Feist                 {
995*5f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
996*5f2caaefSJames Feist                                      << ", Illegal Property "
997*5f2caaefSJames Feist                                      << jsonData.dump();
99883ff9ab6SJames Feist                     return;
99983ff9ab6SJames Feist                 }
1000*5f2caaefSJames Feist                 std::array<
1001*5f2caaefSJames Feist                     std::pair<const char*, std::optional<nlohmann::json>*>, 4>
1002*5f2caaefSJames Feist                     sections = {
1003*5f2caaefSJames Feist                         std::make_pair("PidControllers", &pidControllers),
1004*5f2caaefSJames Feist                         std::make_pair("FanControllers", &fanControllers),
1005*5f2caaefSJames Feist                         std::make_pair("FanZones", &fanZones),
1006*5f2caaefSJames Feist                         std::make_pair("StepwiseControllers",
1007*5f2caaefSJames Feist                                        &stepwiseControllers)};
1008*5f2caaefSJames Feist 
1009*5f2caaefSJames Feist                 for (auto& containerPair : sections)
101083ff9ab6SJames Feist                 {
1011*5f2caaefSJames Feist                     auto& container = *(containerPair.second);
1012*5f2caaefSJames Feist                     if (!container)
1013*5f2caaefSJames Feist                     {
1014*5f2caaefSJames Feist                         continue;
1015*5f2caaefSJames Feist                     }
1016*5f2caaefSJames Feist                     const char* type = containerPair.first;
1017*5f2caaefSJames Feist 
1018*5f2caaefSJames Feist                     for (auto& record : container->items())
1019*5f2caaefSJames Feist                     {
1020*5f2caaefSJames Feist                         const auto& name = record.key();
102183ff9ab6SJames Feist                         auto pathItr =
102283ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
102383ff9ab6SJames Feist                                          [&name](const auto& obj) {
102483ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
102583ff9ab6SJames Feist                                                  obj.first.str, name);
102683ff9ab6SJames Feist                                          });
102783ff9ab6SJames Feist                         boost::container::flat_map<
102883ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
102983ff9ab6SJames Feist                             output;
103083ff9ab6SJames Feist 
103183ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
103283ff9ab6SJames Feist 
103383ff9ab6SJames Feist                         // determines if we're patching entity-manager or
103483ff9ab6SJames Feist                         // creating a new object
103583ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
1036*5f2caaefSJames Feist                         std::string iface;
1037*5f2caaefSJames Feist                         if (type == "PidControllers" ||
1038*5f2caaefSJames Feist                             type == "FanControllers")
103983ff9ab6SJames Feist                         {
1040*5f2caaefSJames Feist                             iface = pidConfigurationIface;
104183ff9ab6SJames Feist                             if (!createNewObject &&
104283ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
104383ff9ab6SJames Feist                                     pathItr->second.end())
104483ff9ab6SJames Feist                             {
104583ff9ab6SJames Feist                                 createNewObject = true;
104683ff9ab6SJames Feist                             }
104783ff9ab6SJames Feist                         }
1048*5f2caaefSJames Feist                         else if (type == "FanZones")
1049*5f2caaefSJames Feist                         {
1050*5f2caaefSJames Feist                             iface = pidZoneConfigurationIface;
1051*5f2caaefSJames Feist                             if (!createNewObject &&
105283ff9ab6SJames Feist                                 pathItr->second.find(
105383ff9ab6SJames Feist                                     pidZoneConfigurationIface) ==
105483ff9ab6SJames Feist                                     pathItr->second.end())
105583ff9ab6SJames Feist                             {
1056*5f2caaefSJames Feist 
105783ff9ab6SJames Feist                                 createNewObject = true;
105883ff9ab6SJames Feist                             }
1059*5f2caaefSJames Feist                         }
1060*5f2caaefSJames Feist                         else if (type == "StepwiseControllers")
1061*5f2caaefSJames Feist                         {
1062*5f2caaefSJames Feist                             iface = stepwiseConfigurationIface;
1063*5f2caaefSJames Feist                             if (!createNewObject &&
1064*5f2caaefSJames Feist                                 pathItr->second.find(
1065*5f2caaefSJames Feist                                     stepwiseConfigurationIface) ==
1066*5f2caaefSJames Feist                                     pathItr->second.end())
1067*5f2caaefSJames Feist                             {
1068*5f2caaefSJames Feist                                 createNewObject = true;
1069*5f2caaefSJames Feist                             }
1070*5f2caaefSJames Feist                         }
107183ff9ab6SJames Feist                         output["Name"] =
107283ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
107383ff9ab6SJames Feist 
107483ff9ab6SJames Feist                         std::string chassis;
107583ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
1076*5f2caaefSJames Feist                             response, type, std::move(record.value()),
107783ff9ab6SJames Feist                             pathItr->first.str, managedObj, createNewObject,
107883ff9ab6SJames Feist                             output, chassis);
107983ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
108083ff9ab6SJames Feist                         {
108183ff9ab6SJames Feist                             return;
108283ff9ab6SJames Feist                         }
108383ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
108483ff9ab6SJames Feist                         {
108583ff9ab6SJames Feist                             continue;
108683ff9ab6SJames Feist                         }
108783ff9ab6SJames Feist 
108883ff9ab6SJames Feist                         if (!createNewObject)
108983ff9ab6SJames Feist                         {
109083ff9ab6SJames Feist                             for (const auto& property : output)
109183ff9ab6SJames Feist                             {
109283ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
109383ff9ab6SJames Feist                                     [response,
109483ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
109583ff9ab6SJames Feist                                         const boost::system::error_code ec) {
109683ff9ab6SJames Feist                                         if (ec)
109783ff9ab6SJames Feist                                         {
109883ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
109983ff9ab6SJames Feist                                                 << "Error patching "
110083ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
110135a62c7cSJason M. Bills                                             messages::internalError(
110235a62c7cSJason M. Bills                                                 response->res);
110383ff9ab6SJames Feist                                         }
110483ff9ab6SJames Feist                                     },
110583ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
110683ff9ab6SJames Feist                                     pathItr->first.str,
110783ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
1108*5f2caaefSJames Feist                                     iface, property.first, property.second);
110983ff9ab6SJames Feist                             }
111083ff9ab6SJames Feist                         }
111183ff9ab6SJames Feist                         else
111283ff9ab6SJames Feist                         {
111383ff9ab6SJames Feist                             if (chassis.empty())
111483ff9ab6SJames Feist                             {
111583ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
111683ff9ab6SJames Feist                                     << "Failed to get chassis from config";
111735a62c7cSJason M. Bills                                 messages::invalidObject(response->res, name);
111883ff9ab6SJames Feist                                 return;
111983ff9ab6SJames Feist                             }
112083ff9ab6SJames Feist 
112183ff9ab6SJames Feist                             bool foundChassis = false;
112283ff9ab6SJames Feist                             for (const auto& obj : managedObj)
112383ff9ab6SJames Feist                             {
112483ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
112583ff9ab6SJames Feist                                                                 chassis))
112683ff9ab6SJames Feist                                 {
112783ff9ab6SJames Feist                                     chassis = obj.first.str;
112883ff9ab6SJames Feist                                     foundChassis = true;
112983ff9ab6SJames Feist                                     break;
113083ff9ab6SJames Feist                                 }
113183ff9ab6SJames Feist                             }
113283ff9ab6SJames Feist                             if (!foundChassis)
113383ff9ab6SJames Feist                             {
113483ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
113583ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
113683ff9ab6SJames Feist                                 messages::resourceMissingAtURI(
113735a62c7cSJason M. Bills                                     response->res,
113835a62c7cSJason M. Bills                                     "/redfish/v1/Chassis/" + chassis);
113983ff9ab6SJames Feist                                 return;
114083ff9ab6SJames Feist                             }
114183ff9ab6SJames Feist 
114283ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
114383ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
114483ff9ab6SJames Feist                                     if (ec)
114583ff9ab6SJames Feist                                     {
114683ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
114783ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
114835a62c7cSJason M. Bills                                         messages::internalError(response->res);
114983ff9ab6SJames Feist                                     }
115083ff9ab6SJames Feist                                 },
115183ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
115283ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
115383ff9ab6SJames Feist                                 output);
115483ff9ab6SJames Feist                         }
115583ff9ab6SJames Feist                     }
115683ff9ab6SJames Feist                 }
115783ff9ab6SJames Feist             },
115883ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
115983ff9ab6SJames Feist             "GetManagedObjects");
116083ff9ab6SJames Feist     }
11615b4aa86bSJames Feist 
11625b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
11635b4aa86bSJames Feist                  const std::vector<std::string>& params) override
11645b4aa86bSJames Feist     {
11650627a2c7SEd Tanous         std::optional<nlohmann::json> oem;
11660627a2c7SEd Tanous 
11670627a2c7SEd Tanous         if (!json_util::readJson(req, res, "Oem", oem))
116883ff9ab6SJames Feist         {
116983ff9ab6SJames Feist             return;
117083ff9ab6SJames Feist         }
11710627a2c7SEd Tanous 
117283ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
11730627a2c7SEd Tanous 
11740627a2c7SEd Tanous         if (oem)
117583ff9ab6SJames Feist         {
11760627a2c7SEd Tanous             for (const auto& oemLevel : oem->items())
117783ff9ab6SJames Feist             {
1178*5f2caaefSJames Feist                 std::optional<nlohmann::json> openbmc;
1179*5f2caaefSJames Feist                 if (!redfish::json_util::readJson(*oem, res, "OpenBmc",
1180*5f2caaefSJames Feist                                                   openbmc))
118183ff9ab6SJames Feist                 {
1182*5f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
1183*5f2caaefSJames Feist                                      << ", Illegal Property " << oem->dump();
118483ff9ab6SJames Feist                     return;
118583ff9ab6SJames Feist                 }
1186*5f2caaefSJames Feist                 if (openbmc)
118783ff9ab6SJames Feist                 {
1188*5f2caaefSJames Feist                     std::optional<nlohmann::json> fan;
1189*5f2caaefSJames Feist                     if (!redfish::json_util::readJson(*openbmc, res, "Fan",
1190*5f2caaefSJames Feist                                                       fan))
119183ff9ab6SJames Feist                     {
1192*5f2caaefSJames Feist                         BMCWEB_LOG_ERROR << "Line:" << __LINE__
1193*5f2caaefSJames Feist                                          << ", Illegal Property "
1194*5f2caaefSJames Feist                                          << openbmc->dump();
119583ff9ab6SJames Feist                         return;
119683ff9ab6SJames Feist                     }
1197*5f2caaefSJames Feist                     if (fan)
119883ff9ab6SJames Feist                     {
1199*5f2caaefSJames Feist                         setPidValues(response, *fan);
120083ff9ab6SJames Feist                     }
120183ff9ab6SJames Feist                 }
120283ff9ab6SJames Feist             }
120383ff9ab6SJames Feist         }
12049c310685SBorawski.Lukasz     }
12059c310685SBorawski.Lukasz 
12061abe55efSEd Tanous     std::string getDateTime() const
12071abe55efSEd Tanous     {
12089c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
12099c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
12109c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
12119c310685SBorawski.Lukasz 
12129c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
12131abe55efSEd Tanous                           std::localtime(&time)))
12141abe55efSEd Tanous         {
12159c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
12169c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
12179c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
12189c310685SBorawski.Lukasz         }
12199c310685SBorawski.Lukasz 
12209c310685SBorawski.Lukasz         return redfishDateTime;
12219c310685SBorawski.Lukasz     }
12220f74e643SEd Tanous 
12230f74e643SEd Tanous     std::string uuid;
12249c310685SBorawski.Lukasz };
12259c310685SBorawski.Lukasz 
12261abe55efSEd Tanous class ManagerCollection : public Node
12271abe55efSEd Tanous {
12289c310685SBorawski.Lukasz   public:
12291abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
12301abe55efSEd Tanous     {
1231a434f2bdSEd Tanous         entityPrivileges = {
1232a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
1233e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1234e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1235e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1236e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1237e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
12389c310685SBorawski.Lukasz     }
12399c310685SBorawski.Lukasz 
12409c310685SBorawski.Lukasz   private:
124155c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
12421abe55efSEd Tanous                const std::vector<std::string>& params) override
12431abe55efSEd Tanous     {
124483ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
124583ff9ab6SJames Feist         // because it has a duplicate entry for members
124655c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
124755c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
124855c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
124955c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
125055c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
125155c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
125255c7b7a2SEd Tanous         res.jsonValue["Members"] = {
12535b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
12549c310685SBorawski.Lukasz         res.end();
12559c310685SBorawski.Lukasz     }
12569c310685SBorawski.Lukasz };
12579c310685SBorawski.Lukasz } // namespace redfish
1258