xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision ed5befbd3c70d1e1da8d243ed0830849abfce014)
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 {
25*ed5befbdSJennifer Lee 
26*ed5befbdSJennifer Lee /**
27*ed5befbdSJennifer Lee  * ManagerActionsReset class supports handle POST method for Reset action.
28*ed5befbdSJennifer Lee  * The class retrieves and sends data directly to dbus.
29*ed5befbdSJennifer Lee  */
30*ed5befbdSJennifer Lee class ManagerActionsReset : public Node
31*ed5befbdSJennifer Lee {
32*ed5befbdSJennifer Lee   public:
33*ed5befbdSJennifer Lee     ManagerActionsReset(CrowApp& app) :
34*ed5befbdSJennifer Lee         Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/")
35*ed5befbdSJennifer Lee     {
36*ed5befbdSJennifer Lee         entityPrivileges = {
37*ed5befbdSJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
38*ed5befbdSJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
39*ed5befbdSJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
40*ed5befbdSJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
41*ed5befbdSJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
42*ed5befbdSJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
43*ed5befbdSJennifer Lee     }
44*ed5befbdSJennifer Lee 
45*ed5befbdSJennifer Lee   private:
46*ed5befbdSJennifer Lee     /**
47*ed5befbdSJennifer Lee      * Function handles GET method request.
48*ed5befbdSJennifer Lee      * ManagerActionReset supports for POST method,
49*ed5befbdSJennifer Lee      * it is not required to retrieve more information in GET.
50*ed5befbdSJennifer Lee      */
51*ed5befbdSJennifer Lee     void doGet(crow::Response& res, const crow::Request& req,
52*ed5befbdSJennifer Lee                const std::vector<std::string>& params) override
53*ed5befbdSJennifer Lee     {
54*ed5befbdSJennifer Lee         res.jsonValue = Node::json;
55*ed5befbdSJennifer Lee         res.end();
56*ed5befbdSJennifer Lee     }
57*ed5befbdSJennifer Lee 
58*ed5befbdSJennifer Lee     /**
59*ed5befbdSJennifer Lee      * Function handles POST method request.
60*ed5befbdSJennifer Lee      * Analyzes POST body message before sends Reset request data to dbus.
61*ed5befbdSJennifer Lee      * OpenBMC allows for ResetType is GracefulRestart only.
62*ed5befbdSJennifer Lee      */
63*ed5befbdSJennifer Lee     void doPost(crow::Response& res, const crow::Request& req,
64*ed5befbdSJennifer Lee                 const std::vector<std::string>& params) override
65*ed5befbdSJennifer Lee     {
66*ed5befbdSJennifer Lee         std::string resetType;
67*ed5befbdSJennifer Lee 
68*ed5befbdSJennifer Lee         if (!json_util::readJson(req, res, "ResetType", resetType))
69*ed5befbdSJennifer Lee         {
70*ed5befbdSJennifer Lee             return;
71*ed5befbdSJennifer Lee         }
72*ed5befbdSJennifer Lee 
73*ed5befbdSJennifer Lee         if (resetType != "GracefulRestart")
74*ed5befbdSJennifer Lee         {
75*ed5befbdSJennifer Lee             res.result(boost::beast::http::status::bad_request);
76*ed5befbdSJennifer Lee             messages::actionParameterNotSupported(res, resetType, "ResetType");
77*ed5befbdSJennifer Lee             BMCWEB_LOG_ERROR << "Request incorrect action parameter: "
78*ed5befbdSJennifer Lee                              << resetType;
79*ed5befbdSJennifer Lee             res.end();
80*ed5befbdSJennifer Lee             return;
81*ed5befbdSJennifer Lee         }
82*ed5befbdSJennifer Lee         doBMCGracefulRestart(res, req, params);
83*ed5befbdSJennifer Lee     }
84*ed5befbdSJennifer Lee 
85*ed5befbdSJennifer Lee     /**
86*ed5befbdSJennifer Lee      * Function transceives data with dbus directly.
87*ed5befbdSJennifer Lee      * All BMC state properties will be retrieved before sending reset request.
88*ed5befbdSJennifer Lee      */
89*ed5befbdSJennifer Lee     void doBMCGracefulRestart(crow::Response& res, const crow::Request& req,
90*ed5befbdSJennifer Lee                               const std::vector<std::string>& params)
91*ed5befbdSJennifer Lee     {
92*ed5befbdSJennifer Lee         const char* processName = "xyz.openbmc_project.State.BMC";
93*ed5befbdSJennifer Lee         const char* objectPath = "/xyz/openbmc_project/state/bmc0";
94*ed5befbdSJennifer Lee         const char* interfaceName = "xyz.openbmc_project.State.BMC";
95*ed5befbdSJennifer Lee         const std::string& propertyValue =
96*ed5befbdSJennifer Lee             "xyz.openbmc_project.State.BMC.Transition.Reboot";
97*ed5befbdSJennifer Lee         const char* destProperty = "RequestedBMCTransition";
98*ed5befbdSJennifer Lee 
99*ed5befbdSJennifer Lee         // Create the D-Bus variant for D-Bus call.
100*ed5befbdSJennifer Lee         VariantType dbusPropertyValue(propertyValue);
101*ed5befbdSJennifer Lee 
102*ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
103*ed5befbdSJennifer Lee 
104*ed5befbdSJennifer Lee         crow::connections::systemBus->async_method_call(
105*ed5befbdSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
106*ed5befbdSJennifer Lee                 // Use "Set" method to set the property value.
107*ed5befbdSJennifer Lee                 if (ec)
108*ed5befbdSJennifer Lee                 {
109*ed5befbdSJennifer Lee                     BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec;
110*ed5befbdSJennifer Lee                     messages::internalError(asyncResp->res);
111*ed5befbdSJennifer Lee                     return;
112*ed5befbdSJennifer Lee                 }
113*ed5befbdSJennifer Lee 
114*ed5befbdSJennifer Lee                 messages::success(asyncResp->res);
115*ed5befbdSJennifer Lee             },
116*ed5befbdSJennifer Lee             processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
117*ed5befbdSJennifer Lee             interfaceName, destProperty, dbusPropertyValue);
118*ed5befbdSJennifer Lee     }
119*ed5befbdSJennifer Lee };
120*ed5befbdSJennifer Lee 
1215b4aa86bSJames Feist static constexpr const char* objectManagerIface =
1225b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
1235b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
1245b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1255b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
1265b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
1279c310685SBorawski.Lukasz 
1285b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection,
1295b4aa86bSJames Feist                              const std::string& path,
1305b4aa86bSJames Feist                              std::shared_ptr<AsyncResp> asyncResp)
1315b4aa86bSJames Feist {
1325b4aa86bSJames Feist 
1335b4aa86bSJames Feist     crow::connections::systemBus->async_method_call(
1345b4aa86bSJames Feist         [asyncResp](const boost::system::error_code ec,
1355b4aa86bSJames Feist                     const dbus::utility::ManagedObjectType& managedObj) {
1365b4aa86bSJames Feist             if (ec)
1375b4aa86bSJames Feist             {
1385b4aa86bSJames Feist                 BMCWEB_LOG_ERROR << ec;
1395b4aa86bSJames Feist                 asyncResp->res.jsonValue.clear();
140f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1415b4aa86bSJames Feist                 return;
1425b4aa86bSJames Feist             }
1435b4aa86bSJames Feist             nlohmann::json& configRoot =
1445b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
1455b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
1465b4aa86bSJames Feist             fans["@odata.type"] = "#OemManager.FanControllers";
1475b4aa86bSJames Feist             fans["@odata.context"] =
1485b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanControllers";
1495b4aa86bSJames Feist             fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
1505b4aa86bSJames Feist                                 "Fan/FanControllers";
1515b4aa86bSJames Feist 
1525b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
1535b4aa86bSJames Feist             pids["@odata.type"] = "#OemManager.PidControllers";
1545b4aa86bSJames Feist             pids["@odata.context"] =
1555b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.PidControllers";
1565b4aa86bSJames Feist             pids["@odata.id"] =
1575b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
1585b4aa86bSJames Feist 
1595b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
1605b4aa86bSJames Feist             zones["@odata.id"] =
1615b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
1625b4aa86bSJames Feist             zones["@odata.type"] = "#OemManager.FanZones";
1635b4aa86bSJames Feist             zones["@odata.context"] =
1645b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanZones";
1655b4aa86bSJames Feist             configRoot["@odata.id"] =
1665b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
1675b4aa86bSJames Feist             configRoot["@odata.type"] = "#OemManager.Fan";
1685b4aa86bSJames Feist             configRoot["@odata.context"] =
1695b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.Fan";
1705b4aa86bSJames Feist 
1715b4aa86bSJames Feist             bool propertyError = false;
1725b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
1735b4aa86bSJames Feist             {
1745b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
1755b4aa86bSJames Feist                 {
1765b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
1775b4aa86bSJames Feist                         intfPair.first != pidZoneConfigurationIface)
1785b4aa86bSJames Feist                     {
1795b4aa86bSJames Feist                         continue;
1805b4aa86bSJames Feist                     }
1815b4aa86bSJames Feist                     auto findName = intfPair.second.find("Name");
1825b4aa86bSJames Feist                     if (findName == intfPair.second.end())
1835b4aa86bSJames Feist                     {
1845b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Field missing Name";
185f12894f8SJason M. Bills                         messages::internalError(asyncResp->res, "Name");
1865b4aa86bSJames Feist                         return;
1875b4aa86bSJames Feist                     }
1885b4aa86bSJames Feist                     const std::string* namePtr =
1895b4aa86bSJames Feist                         mapbox::getPtr<const std::string>(findName->second);
1905b4aa86bSJames Feist                     if (namePtr == nullptr)
1915b4aa86bSJames Feist                     {
1925b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Name Field illegal";
1935b4aa86bSJames Feist                         return;
1945b4aa86bSJames Feist                     }
1955b4aa86bSJames Feist 
1965b4aa86bSJames Feist                     std::string name = *namePtr;
1975b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
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";
2155b4aa86bSJames Feist                     }
2165b4aa86bSJames Feist 
2175b4aa86bSJames Feist                     for (const auto& propertyPair : intfPair.second)
2185b4aa86bSJames Feist                     {
2195b4aa86bSJames Feist                         if (propertyPair.first == "Type" ||
2205b4aa86bSJames Feist                             propertyPair.first == "Class" ||
2215b4aa86bSJames Feist                             propertyPair.first == "Name")
2225b4aa86bSJames Feist                         {
2235b4aa86bSJames Feist                             continue;
2245b4aa86bSJames Feist                         }
2255b4aa86bSJames Feist 
2265b4aa86bSJames Feist                         // zones
2275b4aa86bSJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
2285b4aa86bSJames Feist                         {
2295b4aa86bSJames Feist                             const double* ptr = mapbox::getPtr<const double>(
2305b4aa86bSJames Feist                                 propertyPair.second);
2315b4aa86bSJames Feist                             if (ptr == nullptr)
2325b4aa86bSJames Feist                             {
2335b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
2345b4aa86bSJames Feist                                                  << propertyPair.first;
235f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
2365b4aa86bSJames Feist                                 return;
2375b4aa86bSJames Feist                             }
2385b4aa86bSJames Feist                             zones[name][propertyPair.first] = *ptr;
2395b4aa86bSJames Feist                         }
2405b4aa86bSJames Feist 
2415b4aa86bSJames Feist                         // pid and fans are off the same configuration
2425b4aa86bSJames Feist                         if (intfPair.first == pidConfigurationIface)
2435b4aa86bSJames Feist                         {
2445b4aa86bSJames Feist                             const std::string* classPtr = nullptr;
2455b4aa86bSJames Feist                             auto findClass = intfPair.second.find("Class");
2465b4aa86bSJames Feist                             if (findClass != intfPair.second.end())
2475b4aa86bSJames Feist                             {
2485b4aa86bSJames Feist                                 classPtr = mapbox::getPtr<const std::string>(
2495b4aa86bSJames Feist                                     findClass->second);
2505b4aa86bSJames Feist                             }
2515b4aa86bSJames Feist                             if (classPtr == nullptr)
2525b4aa86bSJames Feist                             {
2535b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Pid Class Field illegal";
254f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res,
255f12894f8SJason M. Bills                                                         "Class");
2565b4aa86bSJames Feist                                 return;
2575b4aa86bSJames Feist                             }
2585b4aa86bSJames Feist                             bool isFan = *classPtr == "fan";
2595b4aa86bSJames Feist                             nlohmann::json& element =
2605b4aa86bSJames Feist                                 isFan ? fans[name] : pids[name];
2615b4aa86bSJames Feist                             if (isFan)
2625b4aa86bSJames Feist                             {
2635b4aa86bSJames Feist                                 element["@odata.id"] =
2645b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
2655b4aa86bSJames Feist                                     "OpenBmc/Fan/FanControllers/" +
2665b4aa86bSJames Feist                                     std::string(name);
2675b4aa86bSJames Feist                                 element["@odata.type"] =
2685b4aa86bSJames Feist                                     "#OemManager.FanController";
2695b4aa86bSJames Feist 
2705b4aa86bSJames Feist                                 element["@odata.context"] =
2715b4aa86bSJames Feist                                     "/redfish/v1/"
2725b4aa86bSJames Feist                                     "$metadata#OemManager.FanController";
2735b4aa86bSJames Feist                             }
2745b4aa86bSJames Feist                             else
2755b4aa86bSJames Feist                             {
2765b4aa86bSJames Feist                                 element["@odata.id"] =
2775b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
2785b4aa86bSJames Feist                                     "OpenBmc/Fan/PidControllers/" +
2795b4aa86bSJames Feist                                     std::string(name);
2805b4aa86bSJames Feist                                 element["@odata.type"] =
2815b4aa86bSJames Feist                                     "#OemManager.PidController";
2825b4aa86bSJames Feist                                 element["@odata.context"] =
2835b4aa86bSJames Feist                                     "/redfish/v1/$metadata"
2845b4aa86bSJames Feist                                     "#OemManager.PidController";
2855b4aa86bSJames Feist                             }
2865b4aa86bSJames Feist 
2875b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
2885b4aa86bSJames Feist                             {
2895b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
2905b4aa86bSJames Feist                                     mapbox::getPtr<
2915b4aa86bSJames Feist                                         const std::vector<std::string>>(
2925b4aa86bSJames Feist                                         propertyPair.second);
2935b4aa86bSJames Feist 
2945b4aa86bSJames Feist                                 if (inputs == nullptr)
2955b4aa86bSJames Feist                                 {
2965b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR
2975b4aa86bSJames Feist                                         << "Zones Pid Field Illegal";
298f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res,
299f12894f8SJason M. Bills                                                             "Zones");
3005b4aa86bSJames Feist                                     return;
3015b4aa86bSJames Feist                                 }
3025b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
3035b4aa86bSJames Feist                                 data = nlohmann::json::array();
3045b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
3055b4aa86bSJames Feist                                 {
3065b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
3075b4aa86bSJames Feist                                     data.push_back(
3085b4aa86bSJames Feist                                         {{"@odata.id",
3095b4aa86bSJames Feist                                           "/redfish/v1/Managers/bmc#/Oem/"
3105b4aa86bSJames Feist                                           "OpenBmc/Fan/FanZones/" +
3115b4aa86bSJames Feist                                               itemCopy}});
3125b4aa86bSJames Feist                                 }
3135b4aa86bSJames Feist                             }
3145b4aa86bSJames Feist                             // todo(james): may never happen, but this
3155b4aa86bSJames Feist                             // assumes configuration data referenced in the
3165b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
3175b4aa86bSJames Feist                             // could add another loop to cover all cases,
3185b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
3195b4aa86bSJames Feist                             // bit
3205b4aa86bSJames Feist 
3215b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
3225b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
3235b4aa86bSJames Feist                             {
3245b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
3255b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
3265b4aa86bSJames Feist                                     mapbox::getPtr<
3275b4aa86bSJames Feist                                         const std::vector<std::string>>(
3285b4aa86bSJames Feist                                         propertyPair.second);
3295b4aa86bSJames Feist 
3305b4aa86bSJames Feist                                 if (inputs == nullptr)
3315b4aa86bSJames Feist                                 {
3325b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
3335b4aa86bSJames Feist                                                      << propertyPair.first;
334f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
3355b4aa86bSJames Feist                                     return;
3365b4aa86bSJames Feist                                 }
3375b4aa86bSJames Feist                                 data = *inputs;
3385b4aa86bSJames Feist                             } // doubles
3395b4aa86bSJames Feist                             else if (propertyPair.first ==
3405b4aa86bSJames Feist                                          "FFGainCoefficient" ||
3415b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
3425b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
3435b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
3445b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
3455b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
3465b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
3475b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
3485b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
3495b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
3505b4aa86bSJames Feist                             {
3515b4aa86bSJames Feist                                 const double* ptr =
3525b4aa86bSJames Feist                                     mapbox::getPtr<const double>(
3535b4aa86bSJames Feist                                         propertyPair.second);
3545b4aa86bSJames Feist                                 if (ptr == nullptr)
3555b4aa86bSJames Feist                                 {
3565b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
3575b4aa86bSJames Feist                                                      << propertyPair.first;
358f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
3595b4aa86bSJames Feist                                     return;
3605b4aa86bSJames Feist                                 }
3615b4aa86bSJames Feist                                 element[propertyPair.first] = *ptr;
3625b4aa86bSJames Feist                             }
3635b4aa86bSJames Feist                         }
3645b4aa86bSJames Feist                     }
3655b4aa86bSJames Feist                 }
3665b4aa86bSJames Feist             }
3675b4aa86bSJames Feist         },
3685b4aa86bSJames Feist         connection, path, objectManagerIface, "GetManagedObjects");
3695b4aa86bSJames Feist }
370ca537928SJennifer Lee 
37183ff9ab6SJames Feist enum class CreatePIDRet
37283ff9ab6SJames Feist {
37383ff9ab6SJames Feist     fail,
37483ff9ab6SJames Feist     del,
37583ff9ab6SJames Feist     patch
37683ff9ab6SJames Feist };
37783ff9ab6SJames Feist 
37883ff9ab6SJames Feist static CreatePIDRet createPidInterface(
37983ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
38083ff9ab6SJames Feist     const nlohmann::json& record, const std::string& path,
38183ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
38283ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
38383ff9ab6SJames Feist         output,
38483ff9ab6SJames Feist     std::string& chassis)
38583ff9ab6SJames Feist {
38683ff9ab6SJames Feist 
38783ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
38883ff9ab6SJames Feist     {
38983ff9ab6SJames Feist         if (createNewObject)
39083ff9ab6SJames Feist         {
39183ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
39283ff9ab6SJames Feist                                                        : std::string("fan");
39383ff9ab6SJames Feist             output["Type"] = std::string("Pid");
39483ff9ab6SJames Feist         }
39583ff9ab6SJames Feist         else if (record == nullptr)
39683ff9ab6SJames Feist         {
39783ff9ab6SJames Feist             // delete interface
39883ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
39983ff9ab6SJames Feist                 [response,
40083ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
40183ff9ab6SJames Feist                     if (ec)
40283ff9ab6SJames Feist                     {
40383ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
40483ff9ab6SJames Feist                                          << ec;
40535a62c7cSJason M. Bills                         messages::internalError(response->res);
40683ff9ab6SJames Feist                     }
40783ff9ab6SJames Feist                 },
40883ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
40983ff9ab6SJames Feist                 pidConfigurationIface, "Delete");
41083ff9ab6SJames Feist             return CreatePIDRet::del;
41183ff9ab6SJames Feist         }
41283ff9ab6SJames Feist 
41383ff9ab6SJames Feist         for (auto& field : record.items())
41483ff9ab6SJames Feist         {
41583ff9ab6SJames Feist             if (field.key() == "Zones")
41683ff9ab6SJames Feist             {
41783ff9ab6SJames Feist                 if (!field.value().is_array())
41883ff9ab6SJames Feist                 {
41983ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
42035a62c7cSJason M. Bills                     messages::propertyValueFormatError(
42135a62c7cSJason M. Bills                         response->res, field.value(), field.key());
42283ff9ab6SJames Feist                     return CreatePIDRet::fail;
42383ff9ab6SJames Feist                 }
42483ff9ab6SJames Feist                 std::vector<std::string> inputs;
42583ff9ab6SJames Feist                 for (const auto& odata : field.value().items())
42683ff9ab6SJames Feist                 {
42783ff9ab6SJames Feist                     for (const auto& value : odata.value().items())
42883ff9ab6SJames Feist                     {
42983ff9ab6SJames Feist                         const std::string* path =
43083ff9ab6SJames Feist                             value.value().get_ptr<const std::string*>();
43183ff9ab6SJames Feist                         if (path == nullptr)
43283ff9ab6SJames Feist                         {
43383ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
43483ff9ab6SJames Feist                             messages::propertyValueFormatError(
43535a62c7cSJason M. Bills                                 response->res, field.value().dump(),
43635a62c7cSJason M. Bills                                 field.key());
43783ff9ab6SJames Feist                             return CreatePIDRet::fail;
43883ff9ab6SJames Feist                         }
43983ff9ab6SJames Feist                         std::string input;
44083ff9ab6SJames Feist                         if (!dbus::utility::getNthStringFromPath(*path, 4,
44183ff9ab6SJames Feist                                                                  input))
44283ff9ab6SJames Feist                         {
44383ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Got invalid path " << *path;
44483ff9ab6SJames Feist                             messages::propertyValueFormatError(
44535a62c7cSJason M. Bills                                 response->res, field.value().dump(),
44635a62c7cSJason M. Bills                                 field.key());
44783ff9ab6SJames Feist                             return CreatePIDRet::fail;
44883ff9ab6SJames Feist                         }
44983ff9ab6SJames Feist                         boost::replace_all(input, "_", " ");
45083ff9ab6SJames Feist                         inputs.emplace_back(std::move(input));
45183ff9ab6SJames Feist                     }
45283ff9ab6SJames Feist                 }
45383ff9ab6SJames Feist                 output["Zones"] = std::move(inputs);
45483ff9ab6SJames Feist             }
45583ff9ab6SJames Feist             else if (field.key() == "Inputs" || field.key() == "Outputs")
45683ff9ab6SJames Feist             {
45783ff9ab6SJames Feist                 if (!field.value().is_array())
45883ff9ab6SJames Feist                 {
45983ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
46035a62c7cSJason M. Bills                     messages::propertyValueFormatError(
46135a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
46283ff9ab6SJames Feist                     return CreatePIDRet::fail;
46383ff9ab6SJames Feist                 }
46483ff9ab6SJames Feist                 std::vector<std::string> inputs;
46583ff9ab6SJames Feist                 for (const auto& value : field.value().items())
46683ff9ab6SJames Feist                 {
46783ff9ab6SJames Feist                     const std::string* sensor =
46883ff9ab6SJames Feist                         value.value().get_ptr<const std::string*>();
46983ff9ab6SJames Feist 
47083ff9ab6SJames Feist                     if (sensor == nullptr)
47183ff9ab6SJames Feist                     {
47283ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type "
47383ff9ab6SJames Feist                                          << field.value().dump();
47483ff9ab6SJames Feist                         messages::propertyValueFormatError(
47535a62c7cSJason M. Bills                             response->res, field.value().dump(), field.key());
47683ff9ab6SJames Feist                         return CreatePIDRet::fail;
47783ff9ab6SJames Feist                     }
47883ff9ab6SJames Feist 
47983ff9ab6SJames Feist                     std::string input =
48083ff9ab6SJames Feist                         boost::replace_all_copy(*sensor, "_", " ");
48183ff9ab6SJames Feist                     inputs.push_back(std::move(input));
48283ff9ab6SJames Feist                     // try to find the sensor in the
48383ff9ab6SJames Feist                     // configuration
48483ff9ab6SJames Feist                     if (chassis.empty())
48583ff9ab6SJames Feist                     {
48683ff9ab6SJames Feist                         std::find_if(
48783ff9ab6SJames Feist                             managedObj.begin(), managedObj.end(),
48883ff9ab6SJames Feist                             [&chassis, sensor](const auto& obj) {
48983ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
49083ff9ab6SJames Feist                                                                 *sensor))
49183ff9ab6SJames Feist                                 {
49283ff9ab6SJames Feist                                     return dbus::utility::getNthStringFromPath(
49383ff9ab6SJames Feist                                         obj.first.str, 5, chassis);
49483ff9ab6SJames Feist                                 }
49583ff9ab6SJames Feist                                 return false;
49683ff9ab6SJames Feist                             });
49783ff9ab6SJames Feist                     }
49883ff9ab6SJames Feist                 }
49983ff9ab6SJames Feist                 output[field.key()] = inputs;
50083ff9ab6SJames Feist             }
50183ff9ab6SJames Feist 
50283ff9ab6SJames Feist             // doubles
50383ff9ab6SJames Feist             else if (field.key() == "FFGainCoefficient" ||
50483ff9ab6SJames Feist                      field.key() == "FFOffCoefficient" ||
50583ff9ab6SJames Feist                      field.key() == "ICoefficient" ||
50683ff9ab6SJames Feist                      field.key() == "ILimitMax" || field.key() == "ILimitMin" ||
50783ff9ab6SJames Feist                      field.key() == "OutLimitMax" ||
50883ff9ab6SJames Feist                      field.key() == "OutLimitMin" ||
50983ff9ab6SJames Feist                      field.key() == "PCoefficient" ||
51083ff9ab6SJames Feist                      field.key() == "SetPoint" || field.key() == "SlewNeg" ||
51183ff9ab6SJames Feist                      field.key() == "SlewPos")
51283ff9ab6SJames Feist             {
51383ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
51483ff9ab6SJames Feist                 if (ptr == nullptr)
51583ff9ab6SJames Feist                 {
51683ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
51735a62c7cSJason M. Bills                     messages::propertyValueFormatError(
51835a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
51983ff9ab6SJames Feist                     return CreatePIDRet::fail;
52083ff9ab6SJames Feist                 }
52183ff9ab6SJames Feist                 output[field.key()] = *ptr;
52283ff9ab6SJames Feist             }
52383ff9ab6SJames Feist 
52483ff9ab6SJames Feist             else
52583ff9ab6SJames Feist             {
52683ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
52735a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
52883ff9ab6SJames Feist                 return CreatePIDRet::fail;
52983ff9ab6SJames Feist             }
53083ff9ab6SJames Feist         }
53183ff9ab6SJames Feist     }
53283ff9ab6SJames Feist     else if (type == "FanZones")
53383ff9ab6SJames Feist     {
53483ff9ab6SJames Feist         if (!createNewObject && record == nullptr)
53583ff9ab6SJames Feist         {
53683ff9ab6SJames Feist             // delete interface
53783ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
53883ff9ab6SJames Feist                 [response,
53983ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
54083ff9ab6SJames Feist                     if (ec)
54183ff9ab6SJames Feist                     {
54283ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
54383ff9ab6SJames Feist                                          << ec;
54435a62c7cSJason M. Bills                         messages::internalError(response->res);
54583ff9ab6SJames Feist                     }
54683ff9ab6SJames Feist                 },
54783ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
54883ff9ab6SJames Feist                 pidZoneConfigurationIface, "Delete");
54983ff9ab6SJames Feist             return CreatePIDRet::del;
55083ff9ab6SJames Feist         }
55183ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
55283ff9ab6SJames Feist 
55383ff9ab6SJames Feist         for (auto& field : record.items())
55483ff9ab6SJames Feist         {
55583ff9ab6SJames Feist             if (field.key() == "Chassis")
55683ff9ab6SJames Feist             {
55783ff9ab6SJames Feist                 const std::string* chassisId = nullptr;
55883ff9ab6SJames Feist                 for (const auto& id : field.value().items())
55983ff9ab6SJames Feist                 {
56083ff9ab6SJames Feist                     if (id.key() != "@odata.id")
56183ff9ab6SJames Feist                     {
56283ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << id.key();
56335a62c7cSJason M. Bills                         messages::propertyUnknown(response->res, field.key());
56483ff9ab6SJames Feist                         return CreatePIDRet::fail;
56583ff9ab6SJames Feist                     }
56683ff9ab6SJames Feist                     chassisId = id.value().get_ptr<const std::string*>();
56783ff9ab6SJames Feist                     if (chassisId == nullptr)
56883ff9ab6SJames Feist                     {
56983ff9ab6SJames Feist                         messages::createFailedMissingReqProperties(
57035a62c7cSJason M. Bills                             response->res, field.key());
57183ff9ab6SJames Feist                         return CreatePIDRet::fail;
57283ff9ab6SJames Feist                     }
57383ff9ab6SJames Feist                 }
57483ff9ab6SJames Feist 
57583ff9ab6SJames Feist                 // /refish/v1/chassis/chassis_name/
57683ff9ab6SJames Feist                 if (!dbus::utility::getNthStringFromPath(*chassisId, 3,
57783ff9ab6SJames Feist                                                          chassis))
57883ff9ab6SJames Feist                 {
57983ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId;
58035a62c7cSJason M. Bills                     messages::invalidObject(response->res, *chassisId);
58183ff9ab6SJames Feist                     return CreatePIDRet::fail;
58283ff9ab6SJames Feist                 }
58383ff9ab6SJames Feist             }
58483ff9ab6SJames Feist             else if (field.key() == "FailSafePercent" ||
58583ff9ab6SJames Feist                      field.key() == "MinThermalRpm")
58683ff9ab6SJames Feist             {
58783ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
58883ff9ab6SJames Feist                 if (ptr == nullptr)
58983ff9ab6SJames Feist                 {
59083ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
59135a62c7cSJason M. Bills                     messages::propertyValueFormatError(
59235a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
59383ff9ab6SJames Feist                     return CreatePIDRet::fail;
59483ff9ab6SJames Feist                 }
59583ff9ab6SJames Feist                 output[field.key()] = *ptr;
59683ff9ab6SJames Feist             }
59783ff9ab6SJames Feist             else
59883ff9ab6SJames Feist             {
59983ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
60035a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
60183ff9ab6SJames Feist                 return CreatePIDRet::fail;
60283ff9ab6SJames Feist             }
60383ff9ab6SJames Feist         }
60483ff9ab6SJames Feist     }
60583ff9ab6SJames Feist     else
60683ff9ab6SJames Feist     {
60783ff9ab6SJames Feist         BMCWEB_LOG_ERROR << "Illegal Type " << type;
60835a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
60983ff9ab6SJames Feist         return CreatePIDRet::fail;
61083ff9ab6SJames Feist     }
61183ff9ab6SJames Feist     return CreatePIDRet::patch;
61283ff9ab6SJames Feist }
61383ff9ab6SJames Feist 
6141abe55efSEd Tanous class Manager : public Node
6151abe55efSEd Tanous {
6169c310685SBorawski.Lukasz   public:
6175b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
6181abe55efSEd Tanous     {
6195b4aa86bSJames Feist         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc";
6209c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
6219c310685SBorawski.Lukasz         Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
6225b4aa86bSJames Feist         Node::json["Id"] = "bmc";
6239c310685SBorawski.Lukasz         Node::json["Name"] = "OpenBmc Manager";
6249c310685SBorawski.Lukasz         Node::json["Description"] = "Baseboard Management Controller";
6259c310685SBorawski.Lukasz         Node::json["PowerState"] = "On";
626ca537928SJennifer Lee         Node::json["ManagerType"] = "BMC";
6279c310685SBorawski.Lukasz         Node::json["UUID"] =
62855c7b7a2SEd Tanous             app.template getMiddleware<crow::persistent_data::Middleware>()
62955c7b7a2SEd Tanous                 .systemUuid;
6309c310685SBorawski.Lukasz         Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
631ca537928SJennifer Lee         Node::json["EthernetInterfaces"] = {
6325b4aa86bSJames Feist             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
6333ebd75f7SEd Tanous 
634a434f2bdSEd Tanous         entityPrivileges = {
635a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
636e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
637e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
638e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
639e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
640e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
6415b4aa86bSJames Feist 
6425b4aa86bSJames Feist         // default oem data
6435b4aa86bSJames Feist         nlohmann::json& oem = Node::json["Oem"];
6445b4aa86bSJames Feist         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
6455b4aa86bSJames Feist         oem["@odata.type"] = "#OemManager.Oem";
6465b4aa86bSJames Feist         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
6475b4aa86bSJames Feist         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
6485b4aa86bSJames Feist         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
6495b4aa86bSJames Feist         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
6505b4aa86bSJames Feist         oemOpenbmc["@odata.context"] =
6515b4aa86bSJames Feist             "/redfish/v1/$metadata#OemManager.OpenBmc";
6529c310685SBorawski.Lukasz     }
6539c310685SBorawski.Lukasz 
6549c310685SBorawski.Lukasz   private:
6555b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
6565b4aa86bSJames Feist     {
6575b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
6585b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
6595b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
6605b4aa86bSJames Feist                 if (ec)
6615b4aa86bSJames Feist                 {
6625b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
663f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
6645b4aa86bSJames Feist                     return;
6655b4aa86bSJames Feist                 }
6665b4aa86bSJames Feist 
6675b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
6685b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
6695b4aa86bSJames Feist                     objectMgrPaths;
6706bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
6715b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
6725b4aa86bSJames Feist                 {
6735b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
6745b4aa86bSJames Feist                     {
6756bce33bcSJames Feist                         auto findConnection =
6766bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
6776bce33bcSJames Feist                         if (findConnection != calledConnections.end())
6786bce33bcSJames Feist                         {
6796bce33bcSJames Feist                             break;
6806bce33bcSJames Feist                         }
6815b4aa86bSJames Feist                         for (const std::string& interface :
6825b4aa86bSJames Feist                              connectionGroup.second)
6835b4aa86bSJames Feist                         {
6845b4aa86bSJames Feist                             if (interface == objectManagerIface)
6855b4aa86bSJames Feist                             {
6865b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
6875b4aa86bSJames Feist                                     pathGroup.first;
6885b4aa86bSJames Feist                             }
6895b4aa86bSJames Feist                             // this list is alphabetical, so we
6905b4aa86bSJames Feist                             // should have found the objMgr by now
6915b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
6925b4aa86bSJames Feist                                 interface == pidZoneConfigurationIface)
6935b4aa86bSJames Feist                             {
6945b4aa86bSJames Feist                                 auto findObjMgr =
6955b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
6965b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
6975b4aa86bSJames Feist                                 {
6985b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
6995b4aa86bSJames Feist                                                      << "Has no Object Manager";
7005b4aa86bSJames Feist                                     continue;
7015b4aa86bSJames Feist                                 }
7026bce33bcSJames Feist 
7036bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
7046bce33bcSJames Feist 
7055b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
7065b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
7075b4aa86bSJames Feist                                 break;
7085b4aa86bSJames Feist                             }
7095b4aa86bSJames Feist                         }
7105b4aa86bSJames Feist                     }
7115b4aa86bSJames Feist                 }
7125b4aa86bSJames Feist             },
7135b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
7145b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
7155b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
7165b4aa86bSJames Feist             std::array<const char*, 3>{pidConfigurationIface,
7175b4aa86bSJames Feist                                        pidZoneConfigurationIface,
7185b4aa86bSJames Feist                                        objectManagerIface});
7195b4aa86bSJames Feist     }
7205b4aa86bSJames Feist 
72155c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
7221abe55efSEd Tanous                const std::vector<std::string>& params) override
7231abe55efSEd Tanous     {
724*ed5befbdSJennifer Lee         // Update Actions object.
725*ed5befbdSJennifer Lee         nlohmann::json& manager_reset = Node::json["Actions"]["#Manager.Reset"];
726*ed5befbdSJennifer Lee         manager_reset["target"] =
727*ed5befbdSJennifer Lee             "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
728*ed5befbdSJennifer Lee         manager_reset["ResetType@Redfish.AllowableValues"] = {
729*ed5befbdSJennifer Lee             "GracefulRestart"};
730ca537928SJennifer Lee 
7319c310685SBorawski.Lukasz         Node::json["DateTime"] = getDateTime();
732*ed5befbdSJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
733*ed5befbdSJennifer Lee         asyncResp->res.jsonValue = Node::json;
7345b4aa86bSJames Feist 
735ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
736ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
7375b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
738ca537928SJennifer Lee                 if (ec)
739ca537928SJennifer Lee                 {
740ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
741f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
742ca537928SJennifer Lee                     return;
743ca537928SJennifer Lee                 }
744ca537928SJennifer Lee 
745ca537928SJennifer Lee                 for (auto& objpath : resp)
746ca537928SJennifer Lee                 {
747ca537928SJennifer Lee                     for (auto& interface : objpath.second)
748ca537928SJennifer Lee                     {
749ca537928SJennifer Lee                         // If interface is xyz.openbmc_project.Software.Version,
750ca537928SJennifer Lee                         // this is what we're looking for.
751ca537928SJennifer Lee                         if (interface.first ==
752ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
753ca537928SJennifer Lee                         {
754ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
755ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
756ca537928SJennifer Lee                             for (auto& property : interface.second)
757ca537928SJennifer Lee                             {
758ca537928SJennifer Lee                                 if (property.first == "Version")
759ca537928SJennifer Lee                                 {
760ca537928SJennifer Lee                                     const std::string* value =
761ca537928SJennifer Lee                                         mapbox::getPtr<const std::string>(
762ca537928SJennifer Lee                                             property.second);
763ca537928SJennifer Lee                                     if (value == nullptr)
764ca537928SJennifer Lee                                     {
765ca537928SJennifer Lee                                         continue;
766ca537928SJennifer Lee                                     }
767ca537928SJennifer Lee                                     asyncResp->res
768ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
769ca537928SJennifer Lee                                 }
770ca537928SJennifer Lee                             }
771ca537928SJennifer Lee                         }
772ca537928SJennifer Lee                     }
773ca537928SJennifer Lee                 }
774ca537928SJennifer Lee             },
775ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
776ca537928SJennifer Lee             "/xyz/openbmc_project/software",
777ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7785b4aa86bSJames Feist         getPidValues(asyncResp);
7795b4aa86bSJames Feist     }
78083ff9ab6SJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response,
78183ff9ab6SJames Feist                       const nlohmann::json& data)
78283ff9ab6SJames Feist     {
78383ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
78483ff9ab6SJames Feist         // interface gets more traction
78583ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
78683ff9ab6SJames Feist             [response,
78783ff9ab6SJames Feist              data](const boost::system::error_code ec,
78883ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
78983ff9ab6SJames Feist                 if (ec)
79083ff9ab6SJames Feist                 {
79183ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
79235a62c7cSJason M. Bills                     messages::internalError(response->res);
79383ff9ab6SJames Feist                     return;
79483ff9ab6SJames Feist                 }
79583ff9ab6SJames Feist                 for (const auto& type : data.items())
79683ff9ab6SJames Feist                 {
79783ff9ab6SJames Feist                     if (!type.value().is_object())
79883ff9ab6SJames Feist                     {
79983ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << type.key();
80035a62c7cSJason M. Bills                         messages::propertyValueFormatError(
80135a62c7cSJason M. Bills                             response->res, type.value(), type.key());
80283ff9ab6SJames Feist                         return;
80383ff9ab6SJames Feist                     }
80483ff9ab6SJames Feist                     for (const auto& record : type.value().items())
80583ff9ab6SJames Feist                     {
80683ff9ab6SJames Feist                         const std::string& name = record.key();
80783ff9ab6SJames Feist                         auto pathItr =
80883ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
80983ff9ab6SJames Feist                                          [&name](const auto& obj) {
81083ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
81183ff9ab6SJames Feist                                                  obj.first.str, name);
81283ff9ab6SJames Feist                                          });
81383ff9ab6SJames Feist                         boost::container::flat_map<
81483ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
81583ff9ab6SJames Feist                             output;
81683ff9ab6SJames Feist 
81783ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
81883ff9ab6SJames Feist 
81983ff9ab6SJames Feist                         // determines if we're patching entity-manager or
82083ff9ab6SJames Feist                         // creating a new object
82183ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
82283ff9ab6SJames Feist                         if (type.key() == "PidControllers" ||
82383ff9ab6SJames Feist                             type.key() == "FanControllers")
82483ff9ab6SJames Feist                         {
82583ff9ab6SJames Feist                             if (!createNewObject &&
82683ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
82783ff9ab6SJames Feist                                     pathItr->second.end())
82883ff9ab6SJames Feist                             {
82983ff9ab6SJames Feist                                 createNewObject = true;
83083ff9ab6SJames Feist                             }
83183ff9ab6SJames Feist                         }
83283ff9ab6SJames Feist                         else if (!createNewObject &&
83383ff9ab6SJames Feist                                  pathItr->second.find(
83483ff9ab6SJames Feist                                      pidZoneConfigurationIface) ==
83583ff9ab6SJames Feist                                      pathItr->second.end())
83683ff9ab6SJames Feist                         {
83783ff9ab6SJames Feist                             createNewObject = true;
83883ff9ab6SJames Feist                         }
83983ff9ab6SJames Feist                         output["Name"] =
84083ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
84183ff9ab6SJames Feist 
84283ff9ab6SJames Feist                         std::string chassis;
84383ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
84483ff9ab6SJames Feist                             response, type.key(), record.value(),
84583ff9ab6SJames Feist                             pathItr->first.str, managedObj, createNewObject,
84683ff9ab6SJames Feist                             output, chassis);
84783ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
84883ff9ab6SJames Feist                         {
84983ff9ab6SJames Feist                             return;
85083ff9ab6SJames Feist                         }
85183ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
85283ff9ab6SJames Feist                         {
85383ff9ab6SJames Feist                             continue;
85483ff9ab6SJames Feist                         }
85583ff9ab6SJames Feist 
85683ff9ab6SJames Feist                         if (!createNewObject)
85783ff9ab6SJames Feist                         {
85883ff9ab6SJames Feist                             for (const auto& property : output)
85983ff9ab6SJames Feist                             {
86083ff9ab6SJames Feist                                 const char* iface =
86183ff9ab6SJames Feist                                     type.key() == "FanZones"
86283ff9ab6SJames Feist                                         ? pidZoneConfigurationIface
86383ff9ab6SJames Feist                                         : pidConfigurationIface;
86483ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
86583ff9ab6SJames Feist                                     [response,
86683ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
86783ff9ab6SJames Feist                                         const boost::system::error_code ec) {
86883ff9ab6SJames Feist                                         if (ec)
86983ff9ab6SJames Feist                                         {
87083ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
87183ff9ab6SJames Feist                                                 << "Error patching "
87283ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
87335a62c7cSJason M. Bills                                             messages::internalError(
87435a62c7cSJason M. Bills                                                 response->res);
87583ff9ab6SJames Feist                                         }
87683ff9ab6SJames Feist                                     },
87783ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
87883ff9ab6SJames Feist                                     pathItr->first.str,
87983ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
88083ff9ab6SJames Feist                                     std::string(iface), property.first,
88183ff9ab6SJames Feist                                     property.second);
88283ff9ab6SJames Feist                             }
88383ff9ab6SJames Feist                         }
88483ff9ab6SJames Feist                         else
88583ff9ab6SJames Feist                         {
88683ff9ab6SJames Feist                             if (chassis.empty())
88783ff9ab6SJames Feist                             {
88883ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
88983ff9ab6SJames Feist                                     << "Failed to get chassis from config";
89035a62c7cSJason M. Bills                                 messages::invalidObject(response->res, name);
89183ff9ab6SJames Feist                                 return;
89283ff9ab6SJames Feist                             }
89383ff9ab6SJames Feist 
89483ff9ab6SJames Feist                             bool foundChassis = false;
89583ff9ab6SJames Feist                             for (const auto& obj : managedObj)
89683ff9ab6SJames Feist                             {
89783ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
89883ff9ab6SJames Feist                                                                 chassis))
89983ff9ab6SJames Feist                                 {
90083ff9ab6SJames Feist                                     chassis = obj.first.str;
90183ff9ab6SJames Feist                                     foundChassis = true;
90283ff9ab6SJames Feist                                     break;
90383ff9ab6SJames Feist                                 }
90483ff9ab6SJames Feist                             }
90583ff9ab6SJames Feist                             if (!foundChassis)
90683ff9ab6SJames Feist                             {
90783ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
90883ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
90983ff9ab6SJames Feist                                 messages::resourceMissingAtURI(
91035a62c7cSJason M. Bills                                     response->res,
91135a62c7cSJason M. Bills                                     "/redfish/v1/Chassis/" + chassis);
91283ff9ab6SJames Feist                                 return;
91383ff9ab6SJames Feist                             }
91483ff9ab6SJames Feist 
91583ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
91683ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
91783ff9ab6SJames Feist                                     if (ec)
91883ff9ab6SJames Feist                                     {
91983ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
92083ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
92135a62c7cSJason M. Bills                                         messages::internalError(response->res);
92283ff9ab6SJames Feist                                     }
92383ff9ab6SJames Feist                                 },
92483ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
92583ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
92683ff9ab6SJames Feist                                 output);
92783ff9ab6SJames Feist                         }
92883ff9ab6SJames Feist                     }
92983ff9ab6SJames Feist                 }
93083ff9ab6SJames Feist             },
93183ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
93283ff9ab6SJames Feist             "GetManagedObjects");
93383ff9ab6SJames Feist     }
9345b4aa86bSJames Feist 
9355b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
9365b4aa86bSJames Feist                  const std::vector<std::string>& params) override
9375b4aa86bSJames Feist     {
93883ff9ab6SJames Feist         nlohmann::json patch;
93983ff9ab6SJames Feist         if (!json_util::processJsonFromRequest(res, req, patch))
94083ff9ab6SJames Feist         {
94183ff9ab6SJames Feist             return;
94283ff9ab6SJames Feist         }
94383ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
94483ff9ab6SJames Feist         for (const auto& topLevel : patch.items())
94583ff9ab6SJames Feist         {
94683ff9ab6SJames Feist             if (topLevel.key() == "Oem")
94783ff9ab6SJames Feist             {
94883ff9ab6SJames Feist                 if (!topLevel.value().is_object())
94983ff9ab6SJames Feist                 {
95083ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
95135a62c7cSJason M. Bills                     messages::propertyValueFormatError(
95235a62c7cSJason M. Bills                         response->res, topLevel.key(), "OemManager.Oem");
95383ff9ab6SJames Feist                     return;
95483ff9ab6SJames Feist                 }
95583ff9ab6SJames Feist             }
95683ff9ab6SJames Feist             else
95783ff9ab6SJames Feist             {
95883ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
95935a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, topLevel.key());
96083ff9ab6SJames Feist                 return;
96183ff9ab6SJames Feist             }
96283ff9ab6SJames Feist             for (const auto& oemLevel : topLevel.value().items())
96383ff9ab6SJames Feist             {
96483ff9ab6SJames Feist                 if (oemLevel.key() == "OpenBmc")
96583ff9ab6SJames Feist                 {
96683ff9ab6SJames Feist                     if (!oemLevel.value().is_object())
96783ff9ab6SJames Feist                     {
96883ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
96935a62c7cSJason M. Bills                         messages::propertyValueFormatError(
97035a62c7cSJason M. Bills                             response->res, topLevel.key(),
97135a62c7cSJason M. Bills                             "OemManager.OpenBmc");
97283ff9ab6SJames Feist                         return;
97383ff9ab6SJames Feist                     }
97483ff9ab6SJames Feist                     for (const auto& typeLevel : oemLevel.value().items())
97583ff9ab6SJames Feist                     {
97683ff9ab6SJames Feist 
97783ff9ab6SJames Feist                         if (typeLevel.key() == "Fan")
97883ff9ab6SJames Feist                         {
97983ff9ab6SJames Feist                             if (!typeLevel.value().is_object())
98083ff9ab6SJames Feist                             {
98183ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR << "Bad Patch "
98283ff9ab6SJames Feist                                                  << typeLevel.key();
98383ff9ab6SJames Feist                                 messages::propertyValueFormatError(
98435a62c7cSJason M. Bills                                     response->res, typeLevel.value().dump(),
98535a62c7cSJason M. Bills                                     typeLevel.key());
98683ff9ab6SJames Feist                                 return;
98783ff9ab6SJames Feist                             }
98883ff9ab6SJames Feist                             setPidValues(response,
98983ff9ab6SJames Feist                                          std::move(typeLevel.value()));
99083ff9ab6SJames Feist                         }
99183ff9ab6SJames Feist                         else
99283ff9ab6SJames Feist                         {
99383ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key();
99435a62c7cSJason M. Bills                             messages::propertyUnknown(response->res,
99535a62c7cSJason M. Bills                                                       typeLevel.key());
99683ff9ab6SJames Feist                             return;
99783ff9ab6SJames Feist                         }
99883ff9ab6SJames Feist                     }
99983ff9ab6SJames Feist                 }
100083ff9ab6SJames Feist                 else
100183ff9ab6SJames Feist                 {
100283ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
100335a62c7cSJason M. Bills                     messages::propertyUnknown(response->res, oemLevel.key());
100483ff9ab6SJames Feist                     return;
100583ff9ab6SJames Feist                 }
100683ff9ab6SJames Feist             }
100783ff9ab6SJames Feist         }
10089c310685SBorawski.Lukasz     }
10099c310685SBorawski.Lukasz 
10101abe55efSEd Tanous     std::string getDateTime() const
10111abe55efSEd Tanous     {
10129c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
10139c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
10149c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
10159c310685SBorawski.Lukasz 
10169c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
10171abe55efSEd Tanous                           std::localtime(&time)))
10181abe55efSEd Tanous         {
10199c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
10209c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
10219c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
10229c310685SBorawski.Lukasz         }
10239c310685SBorawski.Lukasz 
10249c310685SBorawski.Lukasz         return redfishDateTime;
10259c310685SBorawski.Lukasz     }
10269c310685SBorawski.Lukasz };
10279c310685SBorawski.Lukasz 
10281abe55efSEd Tanous class ManagerCollection : public Node
10291abe55efSEd Tanous {
10309c310685SBorawski.Lukasz   public:
10311abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
10321abe55efSEd Tanous     {
10339c310685SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/Managers";
10349c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
10359c310685SBorawski.Lukasz         Node::json["@odata.context"] =
10369c310685SBorawski.Lukasz             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
10379c310685SBorawski.Lukasz         Node::json["Name"] = "Manager Collection";
10389c310685SBorawski.Lukasz         Node::json["Members@odata.count"] = 1;
10395b4aa86bSJames Feist         Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}};
10403ebd75f7SEd Tanous 
1041a434f2bdSEd Tanous         entityPrivileges = {
1042a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
1043e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1044e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1045e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1046e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1047e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
10489c310685SBorawski.Lukasz     }
10499c310685SBorawski.Lukasz 
10509c310685SBorawski.Lukasz   private:
105155c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
10521abe55efSEd Tanous                const std::vector<std::string>& params) override
10531abe55efSEd Tanous     {
105483ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
105583ff9ab6SJames Feist         // because it has a duplicate entry for members
105655c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
105755c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
105855c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
105955c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
106055c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
106155c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
106255c7b7a2SEd Tanous         res.jsonValue["Members"] = {
10635b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
10649c310685SBorawski.Lukasz         res.end();
10659c310685SBorawski.Lukasz     }
10669c310685SBorawski.Lukasz };
10679c310685SBorawski.Lukasz } // namespace redfish
1068