xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision d3ec07f80e5c234611580b52c5a92eee7e8394a2)
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>
22abf2add6SEd Tanous #include <variant>
235b4aa86bSJames Feist 
241abe55efSEd Tanous namespace redfish
251abe55efSEd Tanous {
26ed5befbdSJennifer Lee 
27ed5befbdSJennifer Lee /**
28ed5befbdSJennifer Lee  * ManagerActionsReset class supports handle POST method for Reset action.
29ed5befbdSJennifer Lee  * The class retrieves and sends data directly to dbus.
30ed5befbdSJennifer Lee  */
31ed5befbdSJennifer Lee class ManagerActionsReset : public Node
32ed5befbdSJennifer Lee {
33ed5befbdSJennifer Lee   public:
34ed5befbdSJennifer Lee     ManagerActionsReset(CrowApp& app) :
35ed5befbdSJennifer Lee         Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/")
36ed5befbdSJennifer Lee     {
37ed5befbdSJennifer Lee         entityPrivileges = {
38ed5befbdSJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
39ed5befbdSJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
40ed5befbdSJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
41ed5befbdSJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
42ed5befbdSJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
43ed5befbdSJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
44ed5befbdSJennifer Lee     }
45ed5befbdSJennifer Lee 
46ed5befbdSJennifer Lee   private:
47ed5befbdSJennifer Lee     /**
48ed5befbdSJennifer Lee      * Function handles POST method request.
49ed5befbdSJennifer Lee      * Analyzes POST body message before sends Reset request data to dbus.
50ed5befbdSJennifer Lee      * OpenBMC allows for ResetType is GracefulRestart only.
51ed5befbdSJennifer Lee      */
52ed5befbdSJennifer Lee     void doPost(crow::Response& res, const crow::Request& req,
53ed5befbdSJennifer Lee                 const std::vector<std::string>& params) override
54ed5befbdSJennifer Lee     {
55ed5befbdSJennifer Lee         std::string resetType;
56ed5befbdSJennifer Lee 
57ed5befbdSJennifer Lee         if (!json_util::readJson(req, res, "ResetType", resetType))
58ed5befbdSJennifer Lee         {
59ed5befbdSJennifer Lee             return;
60ed5befbdSJennifer Lee         }
61ed5befbdSJennifer Lee 
62ed5befbdSJennifer Lee         if (resetType != "GracefulRestart")
63ed5befbdSJennifer Lee         {
64ed5befbdSJennifer Lee             res.result(boost::beast::http::status::bad_request);
65ed5befbdSJennifer Lee             messages::actionParameterNotSupported(res, resetType, "ResetType");
66ed5befbdSJennifer Lee             BMCWEB_LOG_ERROR << "Request incorrect action parameter: "
67ed5befbdSJennifer Lee                              << resetType;
68ed5befbdSJennifer Lee             res.end();
69ed5befbdSJennifer Lee             return;
70ed5befbdSJennifer Lee         }
71ed5befbdSJennifer Lee         doBMCGracefulRestart(res, req, params);
72ed5befbdSJennifer Lee     }
73ed5befbdSJennifer Lee 
74ed5befbdSJennifer Lee     /**
75ed5befbdSJennifer Lee      * Function transceives data with dbus directly.
76ed5befbdSJennifer Lee      * All BMC state properties will be retrieved before sending reset request.
77ed5befbdSJennifer Lee      */
78ed5befbdSJennifer Lee     void doBMCGracefulRestart(crow::Response& res, const crow::Request& req,
79ed5befbdSJennifer Lee                               const std::vector<std::string>& params)
80ed5befbdSJennifer Lee     {
81ed5befbdSJennifer Lee         const char* processName = "xyz.openbmc_project.State.BMC";
82ed5befbdSJennifer Lee         const char* objectPath = "/xyz/openbmc_project/state/bmc0";
83ed5befbdSJennifer Lee         const char* interfaceName = "xyz.openbmc_project.State.BMC";
84ed5befbdSJennifer Lee         const std::string& propertyValue =
85ed5befbdSJennifer Lee             "xyz.openbmc_project.State.BMC.Transition.Reboot";
86ed5befbdSJennifer Lee         const char* destProperty = "RequestedBMCTransition";
87ed5befbdSJennifer Lee 
88ed5befbdSJennifer Lee         // Create the D-Bus variant for D-Bus call.
89ed5befbdSJennifer Lee         VariantType dbusPropertyValue(propertyValue);
90ed5befbdSJennifer Lee 
91ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
92ed5befbdSJennifer Lee 
93ed5befbdSJennifer Lee         crow::connections::systemBus->async_method_call(
94ed5befbdSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
95ed5befbdSJennifer Lee                 // Use "Set" method to set the property value.
96ed5befbdSJennifer Lee                 if (ec)
97ed5befbdSJennifer Lee                 {
98ed5befbdSJennifer Lee                     BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec;
99ed5befbdSJennifer Lee                     messages::internalError(asyncResp->res);
100ed5befbdSJennifer Lee                     return;
101ed5befbdSJennifer Lee                 }
102ed5befbdSJennifer Lee 
103ed5befbdSJennifer Lee                 messages::success(asyncResp->res);
104ed5befbdSJennifer Lee             },
105ed5befbdSJennifer Lee             processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
106ed5befbdSJennifer Lee             interfaceName, destProperty, dbusPropertyValue);
107ed5befbdSJennifer Lee     }
108ed5befbdSJennifer Lee };
109ed5befbdSJennifer Lee 
1105b4aa86bSJames Feist static constexpr const char* objectManagerIface =
1115b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
1125b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
1135b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1145b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
1155b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
116b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface =
117b7a08d04SJames Feist     "xyz.openbmc_project.Configuration.Stepwise";
1189c310685SBorawski.Lukasz 
1195b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection,
1205b4aa86bSJames Feist                              const std::string& path,
1215b4aa86bSJames Feist                              std::shared_ptr<AsyncResp> asyncResp)
1225b4aa86bSJames Feist {
1235b4aa86bSJames Feist 
1245b4aa86bSJames Feist     crow::connections::systemBus->async_method_call(
1255b4aa86bSJames Feist         [asyncResp](const boost::system::error_code ec,
1265b4aa86bSJames Feist                     const dbus::utility::ManagedObjectType& managedObj) {
1275b4aa86bSJames Feist             if (ec)
1285b4aa86bSJames Feist             {
1295b4aa86bSJames Feist                 BMCWEB_LOG_ERROR << ec;
1305b4aa86bSJames Feist                 asyncResp->res.jsonValue.clear();
131f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1325b4aa86bSJames Feist                 return;
1335b4aa86bSJames Feist             }
1345b4aa86bSJames Feist             nlohmann::json& configRoot =
1355b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
1365b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
1375b4aa86bSJames Feist             fans["@odata.type"] = "#OemManager.FanControllers";
1385b4aa86bSJames Feist             fans["@odata.context"] =
1395b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanControllers";
1405b4aa86bSJames Feist             fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
1415b4aa86bSJames Feist                                 "Fan/FanControllers";
1425b4aa86bSJames Feist 
1435b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
1445b4aa86bSJames Feist             pids["@odata.type"] = "#OemManager.PidControllers";
1455b4aa86bSJames Feist             pids["@odata.context"] =
1465b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.PidControllers";
1475b4aa86bSJames Feist             pids["@odata.id"] =
1485b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
1495b4aa86bSJames Feist 
150b7a08d04SJames Feist             nlohmann::json& stepwise = configRoot["StepwiseControllers"];
151b7a08d04SJames Feist             stepwise["@odata.type"] = "#OemManager.StepwiseControllers";
152b7a08d04SJames Feist             stepwise["@odata.context"] =
153b7a08d04SJames Feist                 "/redfish/v1/$metadata#OemManager.StepwiseControllers";
154b7a08d04SJames Feist             stepwise["@odata.id"] =
155b7a08d04SJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers";
156b7a08d04SJames Feist 
1575b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
1585b4aa86bSJames Feist             zones["@odata.id"] =
1595b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
1605b4aa86bSJames Feist             zones["@odata.type"] = "#OemManager.FanZones";
1615b4aa86bSJames Feist             zones["@odata.context"] =
1625b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanZones";
1635b4aa86bSJames Feist             configRoot["@odata.id"] =
1645b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
1655b4aa86bSJames Feist             configRoot["@odata.type"] = "#OemManager.Fan";
1665b4aa86bSJames Feist             configRoot["@odata.context"] =
1675b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.Fan";
1685b4aa86bSJames Feist 
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 =
187abf2add6SEd Tanous                         std::get_if<std::string>(&findName->second);
1885b4aa86bSJames Feist                     if (namePtr == nullptr)
1895b4aa86bSJames Feist                     {
1905b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Name Field illegal";
191b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
1925b4aa86bSJames Feist                         return;
1935b4aa86bSJames Feist                     }
1945b4aa86bSJames Feist 
1955b4aa86bSJames Feist                     std::string name = *namePtr;
1965b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
197b7a08d04SJames Feist                     nlohmann::json* config = nullptr;
1985b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
1995b4aa86bSJames Feist                     {
2005b4aa86bSJames Feist                         std::string chassis;
2015b4aa86bSJames Feist                         if (!dbus::utility::getNthStringFromPath(
2025b4aa86bSJames Feist                                 pathPair.first.str, 5, chassis))
2035b4aa86bSJames Feist                         {
2045b4aa86bSJames Feist                             chassis = "#IllegalValue";
2055b4aa86bSJames Feist                         }
2065b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
2075b4aa86bSJames Feist                         zone["Chassis"] = {
2085b4aa86bSJames Feist                             {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
2095b4aa86bSJames Feist                         zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
2105b4aa86bSJames Feist                                             "OpenBmc/Fan/FanZones/" +
2115b4aa86bSJames Feist                                             name;
2125b4aa86bSJames Feist                         zone["@odata.type"] = "#OemManager.FanZone";
2135b4aa86bSJames Feist                         zone["@odata.context"] =
2145b4aa86bSJames Feist                             "/redfish/v1/$metadata#OemManager.FanZone";
215b7a08d04SJames Feist                         config = &zone;
2165b4aa86bSJames Feist                     }
2175b4aa86bSJames Feist 
218b7a08d04SJames Feist                     else if (intfPair.first == stepwiseConfigurationIface)
2195b4aa86bSJames Feist                     {
220b7a08d04SJames Feist                         nlohmann::json& controller = stepwise[name];
221b7a08d04SJames Feist                         config = &controller;
2225b4aa86bSJames Feist 
223b7a08d04SJames Feist                         controller["@odata.id"] =
224b7a08d04SJames Feist                             "/redfish/v1/Managers/bmc#/Oem/"
225b7a08d04SJames Feist                             "OpenBmc/Fan/StepwiseControllers/" +
226b7a08d04SJames Feist                             std::string(name);
227b7a08d04SJames Feist                         controller["@odata.type"] =
228b7a08d04SJames Feist                             "#OemManager.StepwiseController";
229b7a08d04SJames Feist 
230b7a08d04SJames Feist                         controller["@odata.context"] =
231b7a08d04SJames Feist                             "/redfish/v1/"
232b7a08d04SJames Feist                             "$metadata#OemManager.StepwiseController";
2335b4aa86bSJames Feist                     }
2345b4aa86bSJames Feist 
2355b4aa86bSJames Feist                     // pid and fans are off the same configuration
236b7a08d04SJames Feist                     else if (intfPair.first == pidConfigurationIface)
2375b4aa86bSJames Feist                     {
2385b4aa86bSJames Feist                         const std::string* classPtr = nullptr;
2395b4aa86bSJames Feist                         auto findClass = intfPair.second.find("Class");
2405b4aa86bSJames Feist                         if (findClass != intfPair.second.end())
2415b4aa86bSJames Feist                         {
242abf2add6SEd Tanous                             classPtr =
243abf2add6SEd Tanous                                 std::get_if<std::string>(&findClass->second);
2445b4aa86bSJames Feist                         }
2455b4aa86bSJames Feist                         if (classPtr == nullptr)
2465b4aa86bSJames Feist                         {
2475b4aa86bSJames Feist                             BMCWEB_LOG_ERROR << "Pid Class Field illegal";
248a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
2495b4aa86bSJames Feist                             return;
2505b4aa86bSJames Feist                         }
2515b4aa86bSJames Feist                         bool isFan = *classPtr == "fan";
2525b4aa86bSJames Feist                         nlohmann::json& element =
2535b4aa86bSJames Feist                             isFan ? fans[name] : pids[name];
254b7a08d04SJames Feist                         config = &element;
2555b4aa86bSJames Feist                         if (isFan)
2565b4aa86bSJames Feist                         {
2575b4aa86bSJames Feist                             element["@odata.id"] =
2585b4aa86bSJames Feist                                 "/redfish/v1/Managers/bmc#/Oem/"
2595b4aa86bSJames Feist                                 "OpenBmc/Fan/FanControllers/" +
2605b4aa86bSJames Feist                                 std::string(name);
2615b4aa86bSJames Feist                             element["@odata.type"] =
2625b4aa86bSJames Feist                                 "#OemManager.FanController";
2635b4aa86bSJames Feist 
2645b4aa86bSJames Feist                             element["@odata.context"] =
2655b4aa86bSJames Feist                                 "/redfish/v1/"
2665b4aa86bSJames Feist                                 "$metadata#OemManager.FanController";
2675b4aa86bSJames Feist                         }
2685b4aa86bSJames Feist                         else
2695b4aa86bSJames Feist                         {
2705b4aa86bSJames Feist                             element["@odata.id"] =
2715b4aa86bSJames Feist                                 "/redfish/v1/Managers/bmc#/Oem/"
2725b4aa86bSJames Feist                                 "OpenBmc/Fan/PidControllers/" +
2735b4aa86bSJames Feist                                 std::string(name);
2745b4aa86bSJames Feist                             element["@odata.type"] =
2755b4aa86bSJames Feist                                 "#OemManager.PidController";
2765b4aa86bSJames Feist                             element["@odata.context"] =
2775b4aa86bSJames Feist                                 "/redfish/v1/$metadata"
2785b4aa86bSJames Feist                                 "#OemManager.PidController";
2795b4aa86bSJames Feist                         }
280b7a08d04SJames Feist                     }
281b7a08d04SJames Feist                     else
282b7a08d04SJames Feist                     {
283b7a08d04SJames Feist                         BMCWEB_LOG_ERROR << "Unexpected configuration";
284b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
285b7a08d04SJames Feist                         return;
286b7a08d04SJames Feist                     }
287b7a08d04SJames Feist 
288b7a08d04SJames Feist                     // used for making maps out of 2 vectors
289b7a08d04SJames Feist                     const std::vector<double>* keys = nullptr;
290b7a08d04SJames Feist                     const std::vector<double>* values = nullptr;
291b7a08d04SJames Feist 
292b7a08d04SJames Feist                     for (const auto& propertyPair : intfPair.second)
293b7a08d04SJames Feist                     {
294b7a08d04SJames Feist                         if (propertyPair.first == "Type" ||
295b7a08d04SJames Feist                             propertyPair.first == "Class" ||
296b7a08d04SJames Feist                             propertyPair.first == "Name")
297b7a08d04SJames Feist                         {
298b7a08d04SJames Feist                             continue;
299b7a08d04SJames Feist                         }
300b7a08d04SJames Feist 
301b7a08d04SJames Feist                         // zones
302b7a08d04SJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
303b7a08d04SJames Feist                         {
304b7a08d04SJames Feist                             const double* ptr =
305abf2add6SEd Tanous                                 std::get_if<double>(&propertyPair.second);
306b7a08d04SJames Feist                             if (ptr == nullptr)
307b7a08d04SJames Feist                             {
308b7a08d04SJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
309b7a08d04SJames Feist                                                  << propertyPair.first;
310b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
311b7a08d04SJames Feist                                 return;
312b7a08d04SJames Feist                             }
313b7a08d04SJames Feist                             (*config)[propertyPair.first] = *ptr;
314b7a08d04SJames Feist                         }
315b7a08d04SJames Feist 
316b7a08d04SJames Feist                         if (intfPair.first == stepwiseConfigurationIface)
317b7a08d04SJames Feist                         {
318b7a08d04SJames Feist                             if (propertyPair.first == "Reading" ||
319b7a08d04SJames Feist                                 propertyPair.first == "Output")
320b7a08d04SJames Feist                             {
321b7a08d04SJames Feist                                 const std::vector<double>* ptr =
322abf2add6SEd Tanous                                     std::get_if<std::vector<double>>(
323b7a08d04SJames Feist                                         &propertyPair.second);
324b7a08d04SJames Feist 
325b7a08d04SJames Feist                                 if (ptr == nullptr)
326b7a08d04SJames Feist                                 {
327b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
328b7a08d04SJames Feist                                                      << propertyPair.first;
329b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
330b7a08d04SJames Feist                                     return;
331b7a08d04SJames Feist                                 }
332b7a08d04SJames Feist 
333b7a08d04SJames Feist                                 if (propertyPair.first == "Reading")
334b7a08d04SJames Feist                                 {
335b7a08d04SJames Feist                                     keys = ptr;
336b7a08d04SJames Feist                                 }
337b7a08d04SJames Feist                                 else
338b7a08d04SJames Feist                                 {
339b7a08d04SJames Feist                                     values = ptr;
340b7a08d04SJames Feist                                 }
341b7a08d04SJames Feist                                 if (keys && values)
342b7a08d04SJames Feist                                 {
343b7a08d04SJames Feist                                     if (keys->size() != values->size())
344b7a08d04SJames Feist                                     {
345b7a08d04SJames Feist                                         BMCWEB_LOG_ERROR
346b7a08d04SJames Feist                                             << "Reading and Output size don't "
347b7a08d04SJames Feist                                                "match ";
348b7a08d04SJames Feist                                         messages::internalError(asyncResp->res);
349b7a08d04SJames Feist                                         return;
350b7a08d04SJames Feist                                     }
351b7a08d04SJames Feist                                     nlohmann::json& steps = (*config)["Steps"];
352b7a08d04SJames Feist                                     steps = nlohmann::json::array();
353b7a08d04SJames Feist                                     for (size_t ii = 0; ii < keys->size(); ii++)
354b7a08d04SJames Feist                                     {
355b7a08d04SJames Feist                                         steps.push_back(
356b7a08d04SJames Feist                                             {{"Target", (*keys)[ii]},
357b7a08d04SJames Feist                                              {"Output", (*values)[ii]}});
358b7a08d04SJames Feist                                     }
359b7a08d04SJames Feist                                 }
360b7a08d04SJames Feist                             }
361b7a08d04SJames Feist                             if (propertyPair.first == "NegativeHysteresis" ||
362b7a08d04SJames Feist                                 propertyPair.first == "PositiveHysteresis")
363b7a08d04SJames Feist                             {
364b7a08d04SJames Feist                                 const double* ptr =
365abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
366b7a08d04SJames Feist                                 if (ptr == nullptr)
367b7a08d04SJames Feist                                 {
368b7a08d04SJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
369b7a08d04SJames Feist                                                      << propertyPair.first;
370b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
371b7a08d04SJames Feist                                     return;
372b7a08d04SJames Feist                                 }
373b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
374b7a08d04SJames Feist                             }
375b7a08d04SJames Feist                         }
376b7a08d04SJames Feist 
377b7a08d04SJames Feist                         // pid and fans are off the same configuration
378b7a08d04SJames Feist                         if (intfPair.first == pidConfigurationIface ||
379b7a08d04SJames Feist                             intfPair.first == stepwiseConfigurationIface)
380b7a08d04SJames Feist                         {
3815b4aa86bSJames Feist 
3825b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
3835b4aa86bSJames Feist                             {
3845b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
385abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
3861b6b96c5SEd Tanous                                         &propertyPair.second);
3875b4aa86bSJames Feist 
3885b4aa86bSJames Feist                                 if (inputs == nullptr)
3895b4aa86bSJames Feist                                 {
3905b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR
3915b4aa86bSJames Feist                                         << "Zones Pid Field Illegal";
392a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
3935b4aa86bSJames Feist                                     return;
3945b4aa86bSJames Feist                                 }
395b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
3965b4aa86bSJames Feist                                 data = nlohmann::json::array();
3975b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
3985b4aa86bSJames Feist                                 {
3995b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
4005b4aa86bSJames Feist                                     data.push_back(
4015b4aa86bSJames Feist                                         {{"@odata.id",
4025b4aa86bSJames Feist                                           "/redfish/v1/Managers/bmc#/Oem/"
4035b4aa86bSJames Feist                                           "OpenBmc/Fan/FanZones/" +
4045b4aa86bSJames Feist                                               itemCopy}});
4055b4aa86bSJames Feist                                 }
4065b4aa86bSJames Feist                             }
4075b4aa86bSJames Feist                             // todo(james): may never happen, but this
4085b4aa86bSJames Feist                             // assumes configuration data referenced in the
4095b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
4105b4aa86bSJames Feist                             // could add another loop to cover all cases,
4115b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
4125b4aa86bSJames Feist                             // bit
4135b4aa86bSJames Feist 
4145b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
4155b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
4165b4aa86bSJames Feist                             {
417b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
4185b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
419abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
4201b6b96c5SEd Tanous                                         &propertyPair.second);
4215b4aa86bSJames Feist 
4225b4aa86bSJames Feist                                 if (inputs == nullptr)
4235b4aa86bSJames Feist                                 {
4245b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
4255b4aa86bSJames Feist                                                      << propertyPair.first;
426f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
4275b4aa86bSJames Feist                                     return;
4285b4aa86bSJames Feist                                 }
4295b4aa86bSJames Feist                                 data = *inputs;
4305b4aa86bSJames Feist                             } // doubles
4315b4aa86bSJames Feist                             else if (propertyPair.first ==
4325b4aa86bSJames Feist                                          "FFGainCoefficient" ||
4335b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
4345b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
4355b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
4365b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
437aad1a257SJames Feist                                      propertyPair.first ==
438aad1a257SJames Feist                                          "PositiveHysteresis" ||
439aad1a257SJames Feist                                      propertyPair.first ==
440aad1a257SJames Feist                                          "NegativeHysteresis" ||
4415b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
4425b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
4435b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
4447625cb81SJames Feist                                      propertyPair.first == "SetPoint" ||
4455b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
4465b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
4475b4aa86bSJames Feist                             {
4485b4aa86bSJames Feist                                 const double* ptr =
449abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
4505b4aa86bSJames Feist                                 if (ptr == nullptr)
4515b4aa86bSJames Feist                                 {
4525b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
4535b4aa86bSJames Feist                                                      << propertyPair.first;
454f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
4555b4aa86bSJames Feist                                     return;
4565b4aa86bSJames Feist                                 }
457b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
4585b4aa86bSJames Feist                             }
4595b4aa86bSJames Feist                         }
4605b4aa86bSJames Feist                     }
4615b4aa86bSJames Feist                 }
4625b4aa86bSJames Feist             }
4635b4aa86bSJames Feist         },
4645b4aa86bSJames Feist         connection, path, objectManagerIface, "GetManagedObjects");
4655b4aa86bSJames Feist }
466ca537928SJennifer Lee 
46783ff9ab6SJames Feist enum class CreatePIDRet
46883ff9ab6SJames Feist {
46983ff9ab6SJames Feist     fail,
47083ff9ab6SJames Feist     del,
47183ff9ab6SJames Feist     patch
47283ff9ab6SJames Feist };
47383ff9ab6SJames Feist 
4745f2caaefSJames Feist static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response,
4755f2caaefSJames Feist                                 std::vector<nlohmann::json>& config,
4765f2caaefSJames Feist                                 std::vector<std::string>& zones)
4775f2caaefSJames Feist {
478b6baeaa4SJames Feist     if (config.empty())
479b6baeaa4SJames Feist     {
480b6baeaa4SJames Feist         BMCWEB_LOG_ERROR << "Empty Zones";
481b6baeaa4SJames Feist         messages::propertyValueFormatError(response->res,
482b6baeaa4SJames Feist                                            nlohmann::json::array(), "Zones");
483b6baeaa4SJames Feist         return false;
484b6baeaa4SJames Feist     }
4855f2caaefSJames Feist     for (auto& odata : config)
4865f2caaefSJames Feist     {
4875f2caaefSJames Feist         std::string path;
4885f2caaefSJames Feist         if (!redfish::json_util::readJson(odata, response->res, "@odata.id",
4895f2caaefSJames Feist                                           path))
4905f2caaefSJames Feist         {
4915f2caaefSJames Feist             return false;
4925f2caaefSJames Feist         }
4935f2caaefSJames Feist         std::string input;
4945f2caaefSJames Feist         if (!dbus::utility::getNthStringFromPath(path, 4, input))
4955f2caaefSJames Feist         {
4965f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Got invalid path " << path;
4975f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Illegal Type Zones";
4985f2caaefSJames Feist             messages::propertyValueFormatError(response->res, odata.dump(),
4995f2caaefSJames Feist                                                "Zones");
5005f2caaefSJames Feist             return false;
5015f2caaefSJames Feist         }
5025f2caaefSJames Feist         boost::replace_all(input, "_", " ");
5035f2caaefSJames Feist         zones.emplace_back(std::move(input));
5045f2caaefSJames Feist     }
5055f2caaefSJames Feist     return true;
5065f2caaefSJames Feist }
5075f2caaefSJames Feist 
508b6baeaa4SJames Feist static bool findChassis(const dbus::utility::ManagedObjectType& managedObj,
509b6baeaa4SJames Feist                         const std::string& value, std::string& chassis)
510b6baeaa4SJames Feist {
511b6baeaa4SJames Feist     BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n";
512b6baeaa4SJames Feist 
513b6baeaa4SJames Feist     std::string escaped = boost::replace_all_copy(value, " ", "_");
514b6baeaa4SJames Feist     escaped = "/" + escaped;
515b6baeaa4SJames Feist     auto it = std::find_if(
516b6baeaa4SJames Feist         managedObj.begin(), managedObj.end(), [&escaped](const auto& obj) {
517b6baeaa4SJames Feist             if (boost::algorithm::ends_with(obj.first.str, escaped))
518b6baeaa4SJames Feist             {
519b6baeaa4SJames Feist                 BMCWEB_LOG_DEBUG << "Matched " << obj.first.str << "\n";
520b6baeaa4SJames Feist                 return true;
521b6baeaa4SJames Feist             }
522b6baeaa4SJames Feist             return false;
523b6baeaa4SJames Feist         });
524b6baeaa4SJames Feist 
525b6baeaa4SJames Feist     if (it == managedObj.end())
526b6baeaa4SJames Feist     {
527b6baeaa4SJames Feist         return false;
528b6baeaa4SJames Feist     }
529b6baeaa4SJames Feist     // 5 comes from <chassis-name> being the 5th element
530b6baeaa4SJames Feist     // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
531b6baeaa4SJames Feist     return dbus::utility::getNthStringFromPath(it->first.str, 5, chassis);
532b6baeaa4SJames Feist }
533b6baeaa4SJames Feist 
53483ff9ab6SJames Feist static CreatePIDRet createPidInterface(
53583ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
536b6baeaa4SJames Feist     nlohmann::json::iterator it, const std::string& path,
53783ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
53883ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
53983ff9ab6SJames Feist         output,
54083ff9ab6SJames Feist     std::string& chassis)
54183ff9ab6SJames Feist {
54283ff9ab6SJames Feist 
5435f2caaefSJames Feist     // common deleter
544b6baeaa4SJames Feist     if (it.value() == nullptr)
5455f2caaefSJames Feist     {
5465f2caaefSJames Feist         std::string iface;
5475f2caaefSJames Feist         if (type == "PidControllers" || type == "FanControllers")
5485f2caaefSJames Feist         {
5495f2caaefSJames Feist             iface = pidConfigurationIface;
5505f2caaefSJames Feist         }
5515f2caaefSJames Feist         else if (type == "FanZones")
5525f2caaefSJames Feist         {
5535f2caaefSJames Feist             iface = pidZoneConfigurationIface;
5545f2caaefSJames Feist         }
5555f2caaefSJames Feist         else if (type == "StepwiseControllers")
5565f2caaefSJames Feist         {
5575f2caaefSJames Feist             iface = stepwiseConfigurationIface;
5585f2caaefSJames Feist         }
5595f2caaefSJames Feist         else
5605f2caaefSJames Feist         {
5615f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type "
5625f2caaefSJames Feist                              << type;
5635f2caaefSJames Feist             messages::propertyUnknown(response->res, type);
5645f2caaefSJames Feist             return CreatePIDRet::fail;
5655f2caaefSJames Feist         }
5665f2caaefSJames Feist         // delete interface
5675f2caaefSJames Feist         crow::connections::systemBus->async_method_call(
5685f2caaefSJames Feist             [response, path](const boost::system::error_code ec) {
5695f2caaefSJames Feist                 if (ec)
5705f2caaefSJames Feist                 {
5715f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec;
5725f2caaefSJames Feist                     messages::internalError(response->res);
573b6baeaa4SJames Feist                     return;
5745f2caaefSJames Feist                 }
575b6baeaa4SJames Feist                 messages::success(response->res);
5765f2caaefSJames Feist             },
5775f2caaefSJames Feist             "xyz.openbmc_project.EntityManager", path, iface, "Delete");
5785f2caaefSJames Feist         return CreatePIDRet::del;
5795f2caaefSJames Feist     }
5805f2caaefSJames Feist 
581b6baeaa4SJames Feist     if (!createNewObject)
582b6baeaa4SJames Feist     {
583b6baeaa4SJames Feist         // if we aren't creating a new object, we should be able to find it on
584b6baeaa4SJames Feist         // d-bus
585b6baeaa4SJames Feist         if (!findChassis(managedObj, it.key(), chassis))
586b6baeaa4SJames Feist         {
587b6baeaa4SJames Feist             BMCWEB_LOG_ERROR << "Failed to get chassis from config patch";
588b6baeaa4SJames Feist             messages::invalidObject(response->res, it.key());
589b6baeaa4SJames Feist             return CreatePIDRet::fail;
590b6baeaa4SJames Feist         }
591b6baeaa4SJames Feist     }
592b6baeaa4SJames Feist 
59383ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
59483ff9ab6SJames Feist     {
59583ff9ab6SJames Feist         if (createNewObject)
59683ff9ab6SJames Feist         {
59783ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
59883ff9ab6SJames Feist                                                        : std::string("fan");
59983ff9ab6SJames Feist             output["Type"] = std::string("Pid");
60083ff9ab6SJames Feist         }
6015f2caaefSJames Feist 
6025f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> zones;
6035f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
6045f2caaefSJames Feist         std::optional<std::vector<std::string>> outputs;
6055f2caaefSJames Feist         std::map<std::string, std::optional<double>> doubles;
6065f2caaefSJames Feist         if (!redfish::json_util::readJson(
607b6baeaa4SJames Feist                 it.value(), response->res, "Inputs", inputs, "Outputs", outputs,
6085f2caaefSJames Feist                 "Zones", zones, "FFGainCoefficient",
6095f2caaefSJames Feist                 doubles["FFGainCoefficient"], "FFOffCoefficient",
6105f2caaefSJames Feist                 doubles["FFOffCoefficient"], "ICoefficient",
6115f2caaefSJames Feist                 doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"],
6125f2caaefSJames Feist                 "ILimitMin", doubles["ILimitMin"], "OutLimitMax",
6135f2caaefSJames Feist                 doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"],
6145f2caaefSJames Feist                 "PCoefficient", doubles["PCoefficient"], "SetPoint",
6155f2caaefSJames Feist                 doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos",
616aad1a257SJames Feist                 doubles["SlewPos"], "PositiveHysteresis",
617aad1a257SJames Feist                 doubles["PositiveHysteresis"], "NegativeHysteresis",
618aad1a257SJames Feist                 doubles["NegativeHysteresis"]))
61983ff9ab6SJames Feist         {
6205f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
621b6baeaa4SJames Feist                              << it.value().dump();
6225f2caaefSJames Feist             return CreatePIDRet::fail;
62383ff9ab6SJames Feist         }
6245f2caaefSJames Feist         if (zones)
6255f2caaefSJames Feist         {
6265f2caaefSJames Feist             std::vector<std::string> zonesStr;
6275f2caaefSJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStr))
6285f2caaefSJames Feist             {
6295f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
6305f2caaefSJames Feist                 return CreatePIDRet::fail;
6315f2caaefSJames Feist             }
632b6baeaa4SJames Feist             if (chassis.empty() &&
633b6baeaa4SJames Feist                 !findChassis(managedObj, zonesStr[0], chassis))
634b6baeaa4SJames Feist             {
635b6baeaa4SJames Feist                 BMCWEB_LOG_ERROR << "Failed to get chassis from config patch";
636b6baeaa4SJames Feist                 messages::invalidObject(response->res, it.key());
637b6baeaa4SJames Feist                 return CreatePIDRet::fail;
638b6baeaa4SJames Feist             }
639b6baeaa4SJames Feist 
6405f2caaefSJames Feist             output["Zones"] = std::move(zonesStr);
6415f2caaefSJames Feist         }
6425f2caaefSJames Feist         if (inputs || outputs)
6435f2caaefSJames Feist         {
6445f2caaefSJames Feist             std::array<std::optional<std::vector<std::string>>*, 2> containers =
6455f2caaefSJames Feist                 {&inputs, &outputs};
6465f2caaefSJames Feist             size_t index = 0;
6475f2caaefSJames Feist             for (const auto& containerPtr : containers)
6485f2caaefSJames Feist             {
6495f2caaefSJames Feist                 std::optional<std::vector<std::string>>& container =
6505f2caaefSJames Feist                     *containerPtr;
6515f2caaefSJames Feist                 if (!container)
6525f2caaefSJames Feist                 {
6535f2caaefSJames Feist                     index++;
6545f2caaefSJames Feist                     continue;
65583ff9ab6SJames Feist                 }
65683ff9ab6SJames Feist 
6575f2caaefSJames Feist                 for (std::string& value : *container)
65883ff9ab6SJames Feist                 {
6595f2caaefSJames Feist                     boost::replace_all(value, "_", " ");
66083ff9ab6SJames Feist                 }
6615f2caaefSJames Feist                 std::string key;
6625f2caaefSJames Feist                 if (index == 0)
6635f2caaefSJames Feist                 {
6645f2caaefSJames Feist                     key = "Inputs";
6655f2caaefSJames Feist                 }
6665f2caaefSJames Feist                 else
6675f2caaefSJames Feist                 {
6685f2caaefSJames Feist                     key = "Outputs";
6695f2caaefSJames Feist                 }
6705f2caaefSJames Feist                 output[key] = *container;
6715f2caaefSJames Feist                 index++;
6725f2caaefSJames Feist             }
67383ff9ab6SJames Feist         }
67483ff9ab6SJames Feist 
67583ff9ab6SJames Feist         // doubles
6765f2caaefSJames Feist         for (const auto& pairs : doubles)
67783ff9ab6SJames Feist         {
6785f2caaefSJames Feist             if (!pairs.second)
67983ff9ab6SJames Feist             {
6805f2caaefSJames Feist                 continue;
68183ff9ab6SJames Feist             }
6825f2caaefSJames Feist             BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second;
6835f2caaefSJames Feist             output[pairs.first] = *(pairs.second);
6845f2caaefSJames Feist         }
68583ff9ab6SJames Feist     }
68683ff9ab6SJames Feist 
68783ff9ab6SJames Feist     else if (type == "FanZones")
68883ff9ab6SJames Feist     {
68983ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
69083ff9ab6SJames Feist 
6915f2caaefSJames Feist         std::optional<nlohmann::json> chassisContainer;
6925f2caaefSJames Feist         std::optional<double> failSafePercent;
693*d3ec07f8SJames Feist         std::optional<double> minThermalOutput;
694b6baeaa4SJames Feist         if (!redfish::json_util::readJson(it.value(), response->res, "Chassis",
6955f2caaefSJames Feist                                           chassisContainer, "FailSafePercent",
696*d3ec07f8SJames Feist                                           failSafePercent, "MinThermalOutput",
697*d3ec07f8SJames Feist                                           minThermalOutput))
69883ff9ab6SJames Feist         {
6995f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
700b6baeaa4SJames Feist                              << it.value().dump();
70183ff9ab6SJames Feist             return CreatePIDRet::fail;
70283ff9ab6SJames Feist         }
7035f2caaefSJames Feist 
7045f2caaefSJames Feist         if (chassisContainer)
70583ff9ab6SJames Feist         {
7065f2caaefSJames Feist 
7075f2caaefSJames Feist             std::string chassisId;
7085f2caaefSJames Feist             if (!redfish::json_util::readJson(*chassisContainer, response->res,
7095f2caaefSJames Feist                                               "@odata.id", chassisId))
7105f2caaefSJames Feist             {
7115f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
7125f2caaefSJames Feist                                  << chassisContainer->dump();
71383ff9ab6SJames Feist                 return CreatePIDRet::fail;
71483ff9ab6SJames Feist             }
71583ff9ab6SJames Feist 
71683ff9ab6SJames Feist             // /refish/v1/chassis/chassis_name/
7175f2caaefSJames Feist             if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis))
71883ff9ab6SJames Feist             {
7195f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Got invalid path " << chassisId;
7205f2caaefSJames Feist                 messages::invalidObject(response->res, chassisId);
72183ff9ab6SJames Feist                 return CreatePIDRet::fail;
72283ff9ab6SJames Feist             }
72383ff9ab6SJames Feist         }
724*d3ec07f8SJames Feist         if (minThermalOutput)
72583ff9ab6SJames Feist         {
726*d3ec07f8SJames Feist             output["MinThermalOutput"] = *minThermalOutput;
7275f2caaefSJames Feist         }
7285f2caaefSJames Feist         if (failSafePercent)
72983ff9ab6SJames Feist         {
7305f2caaefSJames Feist             output["FailSafePercent"] = *failSafePercent;
7315f2caaefSJames Feist         }
7325f2caaefSJames Feist     }
7335f2caaefSJames Feist     else if (type == "StepwiseControllers")
7345f2caaefSJames Feist     {
7355f2caaefSJames Feist         output["Type"] = std::string("Stepwise");
7365f2caaefSJames Feist 
7375f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> zones;
7385f2caaefSJames Feist         std::optional<std::vector<nlohmann::json>> steps;
7395f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
7405f2caaefSJames Feist         std::optional<double> positiveHysteresis;
7415f2caaefSJames Feist         std::optional<double> negativeHysteresis;
7425f2caaefSJames Feist         if (!redfish::json_util::readJson(
743b6baeaa4SJames Feist                 it.value(), response->res, "Zones", zones, "Steps", steps,
744b6baeaa4SJames Feist                 "Inputs", inputs, "PositiveHysteresis", positiveHysteresis,
7455f2caaefSJames Feist                 "NegativeHysteresis", negativeHysteresis))
7465f2caaefSJames Feist         {
7475f2caaefSJames Feist             BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
748b6baeaa4SJames Feist                              << it.value().dump();
74983ff9ab6SJames Feist             return CreatePIDRet::fail;
75083ff9ab6SJames Feist         }
7515f2caaefSJames Feist 
7525f2caaefSJames Feist         if (zones)
75383ff9ab6SJames Feist         {
754b6baeaa4SJames Feist             std::vector<std::string> zonesStrs;
755b6baeaa4SJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStrs))
7565f2caaefSJames Feist             {
7575f2caaefSJames Feist                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
75883ff9ab6SJames Feist                 return CreatePIDRet::fail;
75983ff9ab6SJames Feist             }
760b6baeaa4SJames Feist             if (chassis.empty() &&
761b6baeaa4SJames Feist                 !findChassis(managedObj, zonesStrs[0], chassis))
762b6baeaa4SJames Feist             {
763b6baeaa4SJames Feist                 BMCWEB_LOG_ERROR << "Failed to get chassis from config patch";
764b6baeaa4SJames Feist                 messages::invalidObject(response->res, it.key());
765b6baeaa4SJames Feist                 return CreatePIDRet::fail;
766b6baeaa4SJames Feist             }
767b6baeaa4SJames Feist             output["Zones"] = std::move(zonesStrs);
7685f2caaefSJames Feist         }
7695f2caaefSJames Feist         if (steps)
7705f2caaefSJames Feist         {
7715f2caaefSJames Feist             std::vector<double> readings;
7725f2caaefSJames Feist             std::vector<double> outputs;
7735f2caaefSJames Feist             for (auto& step : *steps)
7745f2caaefSJames Feist             {
7755f2caaefSJames Feist                 double target;
7765f2caaefSJames Feist                 double output;
7775f2caaefSJames Feist 
7785f2caaefSJames Feist                 if (!redfish::json_util::readJson(step, response->res, "Target",
7795f2caaefSJames Feist                                                   target, "Output", output))
7805f2caaefSJames Feist                 {
7815f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
782b6baeaa4SJames Feist                                      << ", Illegal Property "
783b6baeaa4SJames Feist                                      << it.value().dump();
7845f2caaefSJames Feist                     return CreatePIDRet::fail;
7855f2caaefSJames Feist                 }
7865f2caaefSJames Feist                 readings.emplace_back(target);
7875f2caaefSJames Feist                 outputs.emplace_back(output);
7885f2caaefSJames Feist             }
7895f2caaefSJames Feist             output["Reading"] = std::move(readings);
7905f2caaefSJames Feist             output["Output"] = std::move(outputs);
7915f2caaefSJames Feist         }
7925f2caaefSJames Feist         if (inputs)
7935f2caaefSJames Feist         {
7945f2caaefSJames Feist             for (std::string& value : *inputs)
7955f2caaefSJames Feist             {
7965f2caaefSJames Feist                 boost::replace_all(value, "_", " ");
7975f2caaefSJames Feist             }
7985f2caaefSJames Feist             output["Inputs"] = std::move(*inputs);
7995f2caaefSJames Feist         }
8005f2caaefSJames Feist         if (negativeHysteresis)
8015f2caaefSJames Feist         {
8025f2caaefSJames Feist             output["NegativeHysteresis"] = *negativeHysteresis;
8035f2caaefSJames Feist         }
8045f2caaefSJames Feist         if (positiveHysteresis)
8055f2caaefSJames Feist         {
8065f2caaefSJames Feist             output["PositiveHysteresis"] = *positiveHysteresis;
80783ff9ab6SJames Feist         }
80883ff9ab6SJames Feist     }
80983ff9ab6SJames Feist     else
81083ff9ab6SJames Feist     {
8115f2caaefSJames Feist         BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type;
81235a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
81383ff9ab6SJames Feist         return CreatePIDRet::fail;
81483ff9ab6SJames Feist     }
81583ff9ab6SJames Feist     return CreatePIDRet::patch;
81683ff9ab6SJames Feist }
81783ff9ab6SJames Feist 
8181abe55efSEd Tanous class Manager : public Node
8191abe55efSEd Tanous {
8209c310685SBorawski.Lukasz   public:
8215b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
8221abe55efSEd Tanous     {
8230f74e643SEd Tanous         uuid = app.template getMiddleware<crow::persistent_data::Middleware>()
82455c7b7a2SEd Tanous                    .systemUuid;
825a434f2bdSEd Tanous         entityPrivileges = {
826a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
827e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
828e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
829e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
830e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
831e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
8329c310685SBorawski.Lukasz     }
8339c310685SBorawski.Lukasz 
8349c310685SBorawski.Lukasz   private:
8355b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
8365b4aa86bSJames Feist     {
8375b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
8385b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
8395b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
8405b4aa86bSJames Feist                 if (ec)
8415b4aa86bSJames Feist                 {
8425b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
843f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8445b4aa86bSJames Feist                     return;
8455b4aa86bSJames Feist                 }
8465b4aa86bSJames Feist 
8475b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
8485b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
8495b4aa86bSJames Feist                     objectMgrPaths;
8506bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
8515b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
8525b4aa86bSJames Feist                 {
8535b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
8545b4aa86bSJames Feist                     {
8556bce33bcSJames Feist                         auto findConnection =
8566bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
8576bce33bcSJames Feist                         if (findConnection != calledConnections.end())
8586bce33bcSJames Feist                         {
8596bce33bcSJames Feist                             break;
8606bce33bcSJames Feist                         }
8615b4aa86bSJames Feist                         for (const std::string& interface :
8625b4aa86bSJames Feist                              connectionGroup.second)
8635b4aa86bSJames Feist                         {
8645b4aa86bSJames Feist                             if (interface == objectManagerIface)
8655b4aa86bSJames Feist                             {
8665b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
8675b4aa86bSJames Feist                                     pathGroup.first;
8685b4aa86bSJames Feist                             }
8695b4aa86bSJames Feist                             // this list is alphabetical, so we
8705b4aa86bSJames Feist                             // should have found the objMgr by now
8715b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
872b7a08d04SJames Feist                                 interface == pidZoneConfigurationIface ||
873b7a08d04SJames Feist                                 interface == stepwiseConfigurationIface)
8745b4aa86bSJames Feist                             {
8755b4aa86bSJames Feist                                 auto findObjMgr =
8765b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
8775b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
8785b4aa86bSJames Feist                                 {
8795b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
8805b4aa86bSJames Feist                                                      << "Has no Object Manager";
8815b4aa86bSJames Feist                                     continue;
8825b4aa86bSJames Feist                                 }
8836bce33bcSJames Feist 
8846bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
8856bce33bcSJames Feist 
8865b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
8875b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
8885b4aa86bSJames Feist                                 break;
8895b4aa86bSJames Feist                             }
8905b4aa86bSJames Feist                         }
8915b4aa86bSJames Feist                     }
8925b4aa86bSJames Feist                 }
8935b4aa86bSJames Feist             },
8945b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
8955b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
8965b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
897b7a08d04SJames Feist             std::array<const char*, 4>{
898b7a08d04SJames Feist                 pidConfigurationIface, pidZoneConfigurationIface,
899b7a08d04SJames Feist                 objectManagerIface, stepwiseConfigurationIface});
9005b4aa86bSJames Feist     }
9015b4aa86bSJames Feist 
90255c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
9031abe55efSEd Tanous                const std::vector<std::string>& params) override
9041abe55efSEd Tanous     {
9050f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc";
9060f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager";
9070f74e643SEd Tanous         res.jsonValue["@odata.context"] =
9080f74e643SEd Tanous             "/redfish/v1/$metadata#Manager.Manager";
9090f74e643SEd Tanous         res.jsonValue["Id"] = "bmc";
9100f74e643SEd Tanous         res.jsonValue["Name"] = "OpenBmc Manager";
9110f74e643SEd Tanous         res.jsonValue["Description"] = "Baseboard Management Controller";
9120f74e643SEd Tanous         res.jsonValue["PowerState"] = "On";
913029573d4SEd Tanous         res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}};
9140f74e643SEd Tanous         res.jsonValue["ManagerType"] = "BMC";
9157517658eSEd Tanous         res.jsonValue["UUID"] = uuid;
9160f74e643SEd Tanous         res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
9170f74e643SEd Tanous 
9180f74e643SEd Tanous         res.jsonValue["LogServices"] = {
9190f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
9200f74e643SEd Tanous 
9210f74e643SEd Tanous         res.jsonValue["NetworkProtocol"] = {
9220f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
9230f74e643SEd Tanous 
9240f74e643SEd Tanous         res.jsonValue["EthernetInterfaces"] = {
9250f74e643SEd Tanous             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
9260f74e643SEd Tanous         // default oem data
9270f74e643SEd Tanous         nlohmann::json& oem = res.jsonValue["Oem"];
9280f74e643SEd Tanous         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
9290f74e643SEd Tanous         oem["@odata.type"] = "#OemManager.Oem";
9300f74e643SEd Tanous         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
9310f74e643SEd Tanous         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
9320f74e643SEd Tanous         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
9330f74e643SEd Tanous         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
9340f74e643SEd Tanous         oemOpenbmc["@odata.context"] =
9350f74e643SEd Tanous             "/redfish/v1/$metadata#OemManager.OpenBmc";
9360f74e643SEd Tanous 
937ed5befbdSJennifer Lee         // Update Actions object.
9380f74e643SEd Tanous         nlohmann::json& manager_reset =
9390f74e643SEd Tanous             res.jsonValue["Actions"]["#Manager.Reset"];
940ed5befbdSJennifer Lee         manager_reset["target"] =
941ed5befbdSJennifer Lee             "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
942ed5befbdSJennifer Lee         manager_reset["ResetType@Redfish.AllowableValues"] = {
943ed5befbdSJennifer Lee             "GracefulRestart"};
944ca537928SJennifer Lee 
9450f74e643SEd Tanous         res.jsonValue["DateTime"] = getDateTime();
946029573d4SEd Tanous         res.jsonValue["Links"] = {
947029573d4SEd Tanous             {"ManagerForServers@odata.count", 1},
948029573d4SEd Tanous             {"ManagerForServers",
949029573d4SEd Tanous              {{{"@odata.id", "/redfish/v1/Systems/system"}}}},
950029573d4SEd Tanous             {"ManagerForServers", nlohmann::json::array()}};
951ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
9525b4aa86bSJames Feist 
953ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
954ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
9555b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
956ca537928SJennifer Lee                 if (ec)
957ca537928SJennifer Lee                 {
958ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
959f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
960ca537928SJennifer Lee                     return;
961ca537928SJennifer Lee                 }
962ca537928SJennifer Lee 
963ca537928SJennifer Lee                 for (auto& objpath : resp)
964ca537928SJennifer Lee                 {
965ca537928SJennifer Lee                     for (auto& interface : objpath.second)
966ca537928SJennifer Lee                     {
9675f2caaefSJames Feist                         // If interface is
9685f2caaefSJames Feist                         // xyz.openbmc_project.Software.Version, this is
9695f2caaefSJames Feist                         // what we're looking for.
970ca537928SJennifer Lee                         if (interface.first ==
971ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
972ca537928SJennifer Lee                         {
973ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
974ca537928SJennifer Lee                             for (auto& property : interface.second)
975ca537928SJennifer Lee                             {
976ca537928SJennifer Lee                                 if (property.first == "Version")
977ca537928SJennifer Lee                                 {
978ca537928SJennifer Lee                                     const std::string* value =
979abf2add6SEd Tanous                                         std::get_if<std::string>(
980abf2add6SEd Tanous                                             &property.second);
981ca537928SJennifer Lee                                     if (value == nullptr)
982ca537928SJennifer Lee                                     {
983ca537928SJennifer Lee                                         continue;
984ca537928SJennifer Lee                                     }
985ca537928SJennifer Lee                                     asyncResp->res
986ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
987ca537928SJennifer Lee                                 }
988ca537928SJennifer Lee                             }
989ca537928SJennifer Lee                         }
990ca537928SJennifer Lee                     }
991ca537928SJennifer Lee                 }
992ca537928SJennifer Lee             },
993ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
994ca537928SJennifer Lee             "/xyz/openbmc_project/software",
995ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9965b4aa86bSJames Feist         getPidValues(asyncResp);
9975b4aa86bSJames Feist     }
9985f2caaefSJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data)
99983ff9ab6SJames Feist     {
10005f2caaefSJames Feist 
100183ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
100283ff9ab6SJames Feist         // interface gets more traction
100383ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
100483ff9ab6SJames Feist             [response,
100583ff9ab6SJames Feist              data](const boost::system::error_code ec,
100683ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
100783ff9ab6SJames Feist                 if (ec)
100883ff9ab6SJames Feist                 {
100983ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
101035a62c7cSJason M. Bills                     messages::internalError(response->res);
101183ff9ab6SJames Feist                     return;
101283ff9ab6SJames Feist                 }
10135f2caaefSJames Feist 
10145f2caaefSJames Feist                 // todo(james) mutable doesn't work with asio bindings
10155f2caaefSJames Feist                 nlohmann::json jsonData = data;
10165f2caaefSJames Feist 
10175f2caaefSJames Feist                 std::optional<nlohmann::json> pidControllers;
10185f2caaefSJames Feist                 std::optional<nlohmann::json> fanControllers;
10195f2caaefSJames Feist                 std::optional<nlohmann::json> fanZones;
10205f2caaefSJames Feist                 std::optional<nlohmann::json> stepwiseControllers;
10215f2caaefSJames Feist                 if (!redfish::json_util::readJson(
10225f2caaefSJames Feist                         jsonData, response->res, "PidControllers",
10235f2caaefSJames Feist                         pidControllers, "FanControllers", fanControllers,
10245f2caaefSJames Feist                         "FanZones", fanZones, "StepwiseControllers",
10255f2caaefSJames Feist                         stepwiseControllers))
102683ff9ab6SJames Feist                 {
10275f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
10285f2caaefSJames Feist                                      << ", Illegal Property "
10295f2caaefSJames Feist                                      << jsonData.dump();
103083ff9ab6SJames Feist                     return;
103183ff9ab6SJames Feist                 }
10325f2caaefSJames Feist                 std::array<
103343b761d0SEd Tanous                     std::pair<std::string, std::optional<nlohmann::json>*>, 4>
10345f2caaefSJames Feist                     sections = {
10355f2caaefSJames Feist                         std::make_pair("PidControllers", &pidControllers),
10365f2caaefSJames Feist                         std::make_pair("FanControllers", &fanControllers),
10375f2caaefSJames Feist                         std::make_pair("FanZones", &fanZones),
10385f2caaefSJames Feist                         std::make_pair("StepwiseControllers",
10395f2caaefSJames Feist                                        &stepwiseControllers)};
10405f2caaefSJames Feist 
10415f2caaefSJames Feist                 for (auto& containerPair : sections)
104283ff9ab6SJames Feist                 {
10435f2caaefSJames Feist                     auto& container = *(containerPair.second);
10445f2caaefSJames Feist                     if (!container)
10455f2caaefSJames Feist                     {
10465f2caaefSJames Feist                         continue;
10475f2caaefSJames Feist                     }
104843b761d0SEd Tanous                     std::string& type = containerPair.first;
10495f2caaefSJames Feist 
1050b6baeaa4SJames Feist                     for (nlohmann::json::iterator it = container->begin();
1051b6baeaa4SJames Feist                          it != container->end(); it++)
10525f2caaefSJames Feist                     {
1053b6baeaa4SJames Feist                         const auto& name = it.key();
105483ff9ab6SJames Feist                         auto pathItr =
105583ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
105683ff9ab6SJames Feist                                          [&name](const auto& obj) {
105783ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
1058b6baeaa4SJames Feist                                                  obj.first.str, "/" + name);
105983ff9ab6SJames Feist                                          });
106083ff9ab6SJames Feist                         boost::container::flat_map<
106183ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
106283ff9ab6SJames Feist                             output;
106383ff9ab6SJames Feist 
106483ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
106583ff9ab6SJames Feist 
106683ff9ab6SJames Feist                         // determines if we're patching entity-manager or
106783ff9ab6SJames Feist                         // creating a new object
106883ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
10695f2caaefSJames Feist                         std::string iface;
10705f2caaefSJames Feist                         if (type == "PidControllers" ||
10715f2caaefSJames Feist                             type == "FanControllers")
107283ff9ab6SJames Feist                         {
10735f2caaefSJames Feist                             iface = pidConfigurationIface;
107483ff9ab6SJames Feist                             if (!createNewObject &&
107583ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
107683ff9ab6SJames Feist                                     pathItr->second.end())
107783ff9ab6SJames Feist                             {
107883ff9ab6SJames Feist                                 createNewObject = true;
107983ff9ab6SJames Feist                             }
108083ff9ab6SJames Feist                         }
10815f2caaefSJames Feist                         else if (type == "FanZones")
10825f2caaefSJames Feist                         {
10835f2caaefSJames Feist                             iface = pidZoneConfigurationIface;
10845f2caaefSJames Feist                             if (!createNewObject &&
108583ff9ab6SJames Feist                                 pathItr->second.find(
108683ff9ab6SJames Feist                                     pidZoneConfigurationIface) ==
108783ff9ab6SJames Feist                                     pathItr->second.end())
108883ff9ab6SJames Feist                             {
10895f2caaefSJames Feist 
109083ff9ab6SJames Feist                                 createNewObject = true;
109183ff9ab6SJames Feist                             }
10925f2caaefSJames Feist                         }
10935f2caaefSJames Feist                         else if (type == "StepwiseControllers")
10945f2caaefSJames Feist                         {
10955f2caaefSJames Feist                             iface = stepwiseConfigurationIface;
10965f2caaefSJames Feist                             if (!createNewObject &&
10975f2caaefSJames Feist                                 pathItr->second.find(
10985f2caaefSJames Feist                                     stepwiseConfigurationIface) ==
10995f2caaefSJames Feist                                     pathItr->second.end())
11005f2caaefSJames Feist                             {
11015f2caaefSJames Feist                                 createNewObject = true;
11025f2caaefSJames Feist                             }
11035f2caaefSJames Feist                         }
1104b6baeaa4SJames Feist                         BMCWEB_LOG_DEBUG << "Create new = " << createNewObject
1105b6baeaa4SJames Feist                                          << "\n";
110683ff9ab6SJames Feist                         output["Name"] =
110783ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
110883ff9ab6SJames Feist 
110983ff9ab6SJames Feist                         std::string chassis;
111083ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
1111b6baeaa4SJames Feist                             response, type, it, pathItr->first.str, managedObj,
1112b6baeaa4SJames Feist                             createNewObject, output, chassis);
111383ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
111483ff9ab6SJames Feist                         {
111583ff9ab6SJames Feist                             return;
111683ff9ab6SJames Feist                         }
111783ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
111883ff9ab6SJames Feist                         {
111983ff9ab6SJames Feist                             continue;
112083ff9ab6SJames Feist                         }
112183ff9ab6SJames Feist 
112283ff9ab6SJames Feist                         if (!createNewObject)
112383ff9ab6SJames Feist                         {
112483ff9ab6SJames Feist                             for (const auto& property : output)
112583ff9ab6SJames Feist                             {
112683ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
112783ff9ab6SJames Feist                                     [response,
112883ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
112983ff9ab6SJames Feist                                         const boost::system::error_code ec) {
113083ff9ab6SJames Feist                                         if (ec)
113183ff9ab6SJames Feist                                         {
113283ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
113383ff9ab6SJames Feist                                                 << "Error patching "
113483ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
113535a62c7cSJason M. Bills                                             messages::internalError(
113635a62c7cSJason M. Bills                                                 response->res);
1137b6baeaa4SJames Feist                                             return;
113883ff9ab6SJames Feist                                         }
1139b6baeaa4SJames Feist                                         messages::success(response->res);
114083ff9ab6SJames Feist                                     },
114183ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
114283ff9ab6SJames Feist                                     pathItr->first.str,
114383ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
11445f2caaefSJames Feist                                     iface, property.first, property.second);
114583ff9ab6SJames Feist                             }
114683ff9ab6SJames Feist                         }
114783ff9ab6SJames Feist                         else
114883ff9ab6SJames Feist                         {
114983ff9ab6SJames Feist                             if (chassis.empty())
115083ff9ab6SJames Feist                             {
115183ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
115283ff9ab6SJames Feist                                     << "Failed to get chassis from config";
115335a62c7cSJason M. Bills                                 messages::invalidObject(response->res, name);
115483ff9ab6SJames Feist                                 return;
115583ff9ab6SJames Feist                             }
115683ff9ab6SJames Feist 
115783ff9ab6SJames Feist                             bool foundChassis = false;
115883ff9ab6SJames Feist                             for (const auto& obj : managedObj)
115983ff9ab6SJames Feist                             {
116083ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
116183ff9ab6SJames Feist                                                                 chassis))
116283ff9ab6SJames Feist                                 {
116383ff9ab6SJames Feist                                     chassis = obj.first.str;
116483ff9ab6SJames Feist                                     foundChassis = true;
116583ff9ab6SJames Feist                                     break;
116683ff9ab6SJames Feist                                 }
116783ff9ab6SJames Feist                             }
116883ff9ab6SJames Feist                             if (!foundChassis)
116983ff9ab6SJames Feist                             {
117083ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
117183ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
117283ff9ab6SJames Feist                                 messages::resourceMissingAtURI(
117335a62c7cSJason M. Bills                                     response->res,
117435a62c7cSJason M. Bills                                     "/redfish/v1/Chassis/" + chassis);
117583ff9ab6SJames Feist                                 return;
117683ff9ab6SJames Feist                             }
117783ff9ab6SJames Feist 
117883ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
117983ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
118083ff9ab6SJames Feist                                     if (ec)
118183ff9ab6SJames Feist                                     {
118283ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
118383ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
118435a62c7cSJason M. Bills                                         messages::internalError(response->res);
1185b6baeaa4SJames Feist                                         return;
118683ff9ab6SJames Feist                                     }
1187b6baeaa4SJames Feist                                     messages::success(response->res);
118883ff9ab6SJames Feist                                 },
118983ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
119083ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
119183ff9ab6SJames Feist                                 output);
119283ff9ab6SJames Feist                         }
119383ff9ab6SJames Feist                     }
119483ff9ab6SJames Feist                 }
119583ff9ab6SJames Feist             },
119683ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
119783ff9ab6SJames Feist             "GetManagedObjects");
119883ff9ab6SJames Feist     }
11995b4aa86bSJames Feist 
12005b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
12015b4aa86bSJames Feist                  const std::vector<std::string>& params) override
12025b4aa86bSJames Feist     {
12030627a2c7SEd Tanous         std::optional<nlohmann::json> oem;
12040627a2c7SEd Tanous 
12050627a2c7SEd Tanous         if (!json_util::readJson(req, res, "Oem", oem))
120683ff9ab6SJames Feist         {
120783ff9ab6SJames Feist             return;
120883ff9ab6SJames Feist         }
12090627a2c7SEd Tanous 
121083ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
12110627a2c7SEd Tanous 
12120627a2c7SEd Tanous         if (oem)
121383ff9ab6SJames Feist         {
12145f2caaefSJames Feist             std::optional<nlohmann::json> openbmc;
121543b761d0SEd Tanous             if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc))
121683ff9ab6SJames Feist             {
121743b761d0SEd Tanous                 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
121843b761d0SEd Tanous                                  << oem->dump();
121983ff9ab6SJames Feist                 return;
122083ff9ab6SJames Feist             }
12215f2caaefSJames Feist             if (openbmc)
122283ff9ab6SJames Feist             {
12235f2caaefSJames Feist                 std::optional<nlohmann::json> fan;
122443b761d0SEd Tanous                 if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan))
122583ff9ab6SJames Feist                 {
12265f2caaefSJames Feist                     BMCWEB_LOG_ERROR << "Line:" << __LINE__
12275f2caaefSJames Feist                                      << ", Illegal Property "
12285f2caaefSJames Feist                                      << openbmc->dump();
122983ff9ab6SJames Feist                     return;
123083ff9ab6SJames Feist                 }
12315f2caaefSJames Feist                 if (fan)
123283ff9ab6SJames Feist                 {
12335f2caaefSJames Feist                     setPidValues(response, *fan);
123483ff9ab6SJames Feist                 }
123583ff9ab6SJames Feist             }
123683ff9ab6SJames Feist         }
123783ff9ab6SJames Feist     }
12389c310685SBorawski.Lukasz 
12391abe55efSEd Tanous     std::string getDateTime() const
12401abe55efSEd Tanous     {
12419c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
12429c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
12439c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
12449c310685SBorawski.Lukasz 
12459c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
12461abe55efSEd Tanous                           std::localtime(&time)))
12471abe55efSEd Tanous         {
12489c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
12499c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
12509c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
12519c310685SBorawski.Lukasz         }
12529c310685SBorawski.Lukasz 
12539c310685SBorawski.Lukasz         return redfishDateTime;
12549c310685SBorawski.Lukasz     }
12550f74e643SEd Tanous 
12560f74e643SEd Tanous     std::string uuid;
12579c310685SBorawski.Lukasz };
12589c310685SBorawski.Lukasz 
12591abe55efSEd Tanous class ManagerCollection : public Node
12601abe55efSEd Tanous {
12619c310685SBorawski.Lukasz   public:
12621abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
12631abe55efSEd Tanous     {
1264a434f2bdSEd Tanous         entityPrivileges = {
1265a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
1266e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1267e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1268e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1269e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1270e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
12719c310685SBorawski.Lukasz     }
12729c310685SBorawski.Lukasz 
12739c310685SBorawski.Lukasz   private:
127455c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
12751abe55efSEd Tanous                const std::vector<std::string>& params) override
12761abe55efSEd Tanous     {
127783ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
127883ff9ab6SJames Feist         // because it has a duplicate entry for members
127955c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
128055c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
128155c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
128255c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
128355c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
128455c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
128555c7b7a2SEd Tanous         res.jsonValue["Members"] = {
12865b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
12879c310685SBorawski.Lukasz         res.end();
12889c310685SBorawski.Lukasz     }
12899c310685SBorawski.Lukasz };
12909c310685SBorawski.Lukasz } // namespace redfish
1291