xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision 83ff9ab6a5ef4af27ec47df9dad54d160df49f04)
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 {
255b4aa86bSJames Feist static constexpr const char* objectManagerIface =
265b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
275b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
285b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
295b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
305b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
319c310685SBorawski.Lukasz 
325b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection,
335b4aa86bSJames Feist                              const std::string& path,
345b4aa86bSJames Feist                              std::shared_ptr<AsyncResp> asyncResp)
355b4aa86bSJames Feist {
365b4aa86bSJames Feist 
375b4aa86bSJames Feist     crow::connections::systemBus->async_method_call(
385b4aa86bSJames Feist         [asyncResp](const boost::system::error_code ec,
395b4aa86bSJames Feist                     const dbus::utility::ManagedObjectType& managedObj) {
405b4aa86bSJames Feist             if (ec)
415b4aa86bSJames Feist             {
425b4aa86bSJames Feist                 BMCWEB_LOG_ERROR << ec;
435b4aa86bSJames Feist                 asyncResp->res.jsonValue.clear();
44f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
455b4aa86bSJames Feist                 return;
465b4aa86bSJames Feist             }
475b4aa86bSJames Feist             nlohmann::json& configRoot =
485b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
495b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
505b4aa86bSJames Feist             fans["@odata.type"] = "#OemManager.FanControllers";
515b4aa86bSJames Feist             fans["@odata.context"] =
525b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanControllers";
535b4aa86bSJames Feist             fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
545b4aa86bSJames Feist                                 "Fan/FanControllers";
555b4aa86bSJames Feist 
565b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
575b4aa86bSJames Feist             pids["@odata.type"] = "#OemManager.PidControllers";
585b4aa86bSJames Feist             pids["@odata.context"] =
595b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.PidControllers";
605b4aa86bSJames Feist             pids["@odata.id"] =
615b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
625b4aa86bSJames Feist 
635b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
645b4aa86bSJames Feist             zones["@odata.id"] =
655b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
665b4aa86bSJames Feist             zones["@odata.type"] = "#OemManager.FanZones";
675b4aa86bSJames Feist             zones["@odata.context"] =
685b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanZones";
695b4aa86bSJames Feist             configRoot["@odata.id"] =
705b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
715b4aa86bSJames Feist             configRoot["@odata.type"] = "#OemManager.Fan";
725b4aa86bSJames Feist             configRoot["@odata.context"] =
735b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.Fan";
745b4aa86bSJames Feist 
755b4aa86bSJames Feist             bool propertyError = false;
765b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
775b4aa86bSJames Feist             {
785b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
795b4aa86bSJames Feist                 {
805b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
815b4aa86bSJames Feist                         intfPair.first != pidZoneConfigurationIface)
825b4aa86bSJames Feist                     {
835b4aa86bSJames Feist                         continue;
845b4aa86bSJames Feist                     }
855b4aa86bSJames Feist                     auto findName = intfPair.second.find("Name");
865b4aa86bSJames Feist                     if (findName == intfPair.second.end())
875b4aa86bSJames Feist                     {
885b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Field missing Name";
89f12894f8SJason M. Bills                         messages::internalError(asyncResp->res, "Name");
905b4aa86bSJames Feist                         return;
915b4aa86bSJames Feist                     }
925b4aa86bSJames Feist                     const std::string* namePtr =
935b4aa86bSJames Feist                         mapbox::getPtr<const std::string>(findName->second);
945b4aa86bSJames Feist                     if (namePtr == nullptr)
955b4aa86bSJames Feist                     {
965b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Name Field illegal";
975b4aa86bSJames Feist                         return;
985b4aa86bSJames Feist                     }
995b4aa86bSJames Feist 
1005b4aa86bSJames Feist                     std::string name = *namePtr;
1015b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
1025b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
1035b4aa86bSJames Feist                     {
1045b4aa86bSJames Feist                         std::string chassis;
1055b4aa86bSJames Feist                         if (!dbus::utility::getNthStringFromPath(
1065b4aa86bSJames Feist                                 pathPair.first.str, 5, chassis))
1075b4aa86bSJames Feist                         {
1085b4aa86bSJames Feist                             chassis = "#IllegalValue";
1095b4aa86bSJames Feist                         }
1105b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
1115b4aa86bSJames Feist                         zone["Chassis"] = {
1125b4aa86bSJames Feist                             {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
1135b4aa86bSJames Feist                         zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
1145b4aa86bSJames Feist                                             "OpenBmc/Fan/FanZones/" +
1155b4aa86bSJames Feist                                             name;
1165b4aa86bSJames Feist                         zone["@odata.type"] = "#OemManager.FanZone";
1175b4aa86bSJames Feist                         zone["@odata.context"] =
1185b4aa86bSJames Feist                             "/redfish/v1/$metadata#OemManager.FanZone";
1195b4aa86bSJames Feist                     }
1205b4aa86bSJames Feist 
1215b4aa86bSJames Feist                     for (const auto& propertyPair : intfPair.second)
1225b4aa86bSJames Feist                     {
1235b4aa86bSJames Feist                         if (propertyPair.first == "Type" ||
1245b4aa86bSJames Feist                             propertyPair.first == "Class" ||
1255b4aa86bSJames Feist                             propertyPair.first == "Name")
1265b4aa86bSJames Feist                         {
1275b4aa86bSJames Feist                             continue;
1285b4aa86bSJames Feist                         }
1295b4aa86bSJames Feist 
1305b4aa86bSJames Feist                         // zones
1315b4aa86bSJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
1325b4aa86bSJames Feist                         {
1335b4aa86bSJames Feist                             const double* ptr = mapbox::getPtr<const double>(
1345b4aa86bSJames Feist                                 propertyPair.second);
1355b4aa86bSJames Feist                             if (ptr == nullptr)
1365b4aa86bSJames Feist                             {
1375b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
1385b4aa86bSJames Feist                                                  << propertyPair.first;
139f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1405b4aa86bSJames Feist                                 return;
1415b4aa86bSJames Feist                             }
1425b4aa86bSJames Feist                             zones[name][propertyPair.first] = *ptr;
1435b4aa86bSJames Feist                         }
1445b4aa86bSJames Feist 
1455b4aa86bSJames Feist                         // pid and fans are off the same configuration
1465b4aa86bSJames Feist                         if (intfPair.first == pidConfigurationIface)
1475b4aa86bSJames Feist                         {
1485b4aa86bSJames Feist                             const std::string* classPtr = nullptr;
1495b4aa86bSJames Feist                             auto findClass = intfPair.second.find("Class");
1505b4aa86bSJames Feist                             if (findClass != intfPair.second.end())
1515b4aa86bSJames Feist                             {
1525b4aa86bSJames Feist                                 classPtr = mapbox::getPtr<const std::string>(
1535b4aa86bSJames Feist                                     findClass->second);
1545b4aa86bSJames Feist                             }
1555b4aa86bSJames Feist                             if (classPtr == nullptr)
1565b4aa86bSJames Feist                             {
1575b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Pid Class Field illegal";
158f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res,
159f12894f8SJason M. Bills                                                         "Class");
1605b4aa86bSJames Feist                                 return;
1615b4aa86bSJames Feist                             }
1625b4aa86bSJames Feist                             bool isFan = *classPtr == "fan";
1635b4aa86bSJames Feist                             nlohmann::json& element =
1645b4aa86bSJames Feist                                 isFan ? fans[name] : pids[name];
1655b4aa86bSJames Feist                             if (isFan)
1665b4aa86bSJames Feist                             {
1675b4aa86bSJames Feist                                 element["@odata.id"] =
1685b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
1695b4aa86bSJames Feist                                     "OpenBmc/Fan/FanControllers/" +
1705b4aa86bSJames Feist                                     std::string(name);
1715b4aa86bSJames Feist                                 element["@odata.type"] =
1725b4aa86bSJames Feist                                     "#OemManager.FanController";
1735b4aa86bSJames Feist 
1745b4aa86bSJames Feist                                 element["@odata.context"] =
1755b4aa86bSJames Feist                                     "/redfish/v1/"
1765b4aa86bSJames Feist                                     "$metadata#OemManager.FanController";
1775b4aa86bSJames Feist                             }
1785b4aa86bSJames Feist                             else
1795b4aa86bSJames Feist                             {
1805b4aa86bSJames Feist                                 element["@odata.id"] =
1815b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
1825b4aa86bSJames Feist                                     "OpenBmc/Fan/PidControllers/" +
1835b4aa86bSJames Feist                                     std::string(name);
1845b4aa86bSJames Feist                                 element["@odata.type"] =
1855b4aa86bSJames Feist                                     "#OemManager.PidController";
1865b4aa86bSJames Feist                                 element["@odata.context"] =
1875b4aa86bSJames Feist                                     "/redfish/v1/$metadata"
1885b4aa86bSJames Feist                                     "#OemManager.PidController";
1895b4aa86bSJames Feist                             }
1905b4aa86bSJames Feist 
1915b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
1925b4aa86bSJames Feist                             {
1935b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
1945b4aa86bSJames Feist                                     mapbox::getPtr<
1955b4aa86bSJames Feist                                         const std::vector<std::string>>(
1965b4aa86bSJames Feist                                         propertyPair.second);
1975b4aa86bSJames Feist 
1985b4aa86bSJames Feist                                 if (inputs == nullptr)
1995b4aa86bSJames Feist                                 {
2005b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR
2015b4aa86bSJames Feist                                         << "Zones Pid Field Illegal";
202f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res,
203f12894f8SJason M. Bills                                                             "Zones");
2045b4aa86bSJames Feist                                     return;
2055b4aa86bSJames Feist                                 }
2065b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
2075b4aa86bSJames Feist                                 data = nlohmann::json::array();
2085b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
2095b4aa86bSJames Feist                                 {
2105b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
2115b4aa86bSJames Feist                                     data.push_back(
2125b4aa86bSJames Feist                                         {{"@odata.id",
2135b4aa86bSJames Feist                                           "/redfish/v1/Managers/bmc#/Oem/"
2145b4aa86bSJames Feist                                           "OpenBmc/Fan/FanZones/" +
2155b4aa86bSJames Feist                                               itemCopy}});
2165b4aa86bSJames Feist                                 }
2175b4aa86bSJames Feist                             }
2185b4aa86bSJames Feist                             // todo(james): may never happen, but this
2195b4aa86bSJames Feist                             // assumes configuration data referenced in the
2205b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
2215b4aa86bSJames Feist                             // could add another loop to cover all cases,
2225b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
2235b4aa86bSJames Feist                             // bit
2245b4aa86bSJames Feist 
2255b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
2265b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
2275b4aa86bSJames Feist                             {
2285b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
2295b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
2305b4aa86bSJames Feist                                     mapbox::getPtr<
2315b4aa86bSJames Feist                                         const std::vector<std::string>>(
2325b4aa86bSJames Feist                                         propertyPair.second);
2335b4aa86bSJames Feist 
2345b4aa86bSJames Feist                                 if (inputs == nullptr)
2355b4aa86bSJames Feist                                 {
2365b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
2375b4aa86bSJames Feist                                                      << propertyPair.first;
238f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
2395b4aa86bSJames Feist                                     return;
2405b4aa86bSJames Feist                                 }
2415b4aa86bSJames Feist                                 data = *inputs;
2425b4aa86bSJames Feist                             } // doubles
2435b4aa86bSJames Feist                             else if (propertyPair.first ==
2445b4aa86bSJames Feist                                          "FFGainCoefficient" ||
2455b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
2465b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
2475b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
2485b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
2495b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
2505b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
2515b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
2525b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
2535b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
2545b4aa86bSJames Feist                             {
2555b4aa86bSJames Feist                                 const double* ptr =
2565b4aa86bSJames Feist                                     mapbox::getPtr<const double>(
2575b4aa86bSJames Feist                                         propertyPair.second);
2585b4aa86bSJames Feist                                 if (ptr == nullptr)
2595b4aa86bSJames Feist                                 {
2605b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
2615b4aa86bSJames Feist                                                      << propertyPair.first;
262f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
2635b4aa86bSJames Feist                                     return;
2645b4aa86bSJames Feist                                 }
2655b4aa86bSJames Feist                                 element[propertyPair.first] = *ptr;
2665b4aa86bSJames Feist                             }
2675b4aa86bSJames Feist                         }
2685b4aa86bSJames Feist                     }
2695b4aa86bSJames Feist                 }
2705b4aa86bSJames Feist             }
2715b4aa86bSJames Feist         },
2725b4aa86bSJames Feist         connection, path, objectManagerIface, "GetManagedObjects");
2735b4aa86bSJames Feist }
274ca537928SJennifer Lee 
275*83ff9ab6SJames Feist enum class CreatePIDRet
276*83ff9ab6SJames Feist {
277*83ff9ab6SJames Feist     fail,
278*83ff9ab6SJames Feist     del,
279*83ff9ab6SJames Feist     patch
280*83ff9ab6SJames Feist };
281*83ff9ab6SJames Feist 
282*83ff9ab6SJames Feist static CreatePIDRet createPidInterface(
283*83ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
284*83ff9ab6SJames Feist     const nlohmann::json& record, const std::string& path,
285*83ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
286*83ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
287*83ff9ab6SJames Feist         output,
288*83ff9ab6SJames Feist     std::string& chassis)
289*83ff9ab6SJames Feist {
290*83ff9ab6SJames Feist 
291*83ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
292*83ff9ab6SJames Feist     {
293*83ff9ab6SJames Feist         if (createNewObject)
294*83ff9ab6SJames Feist         {
295*83ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
296*83ff9ab6SJames Feist                                                        : std::string("fan");
297*83ff9ab6SJames Feist             output["Type"] = std::string("Pid");
298*83ff9ab6SJames Feist         }
299*83ff9ab6SJames Feist         else if (record == nullptr)
300*83ff9ab6SJames Feist         {
301*83ff9ab6SJames Feist             // delete interface
302*83ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
303*83ff9ab6SJames Feist                 [response,
304*83ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
305*83ff9ab6SJames Feist                     if (ec)
306*83ff9ab6SJames Feist                     {
307*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
308*83ff9ab6SJames Feist                                          << ec;
309*83ff9ab6SJames Feist                         response->res.result(
310*83ff9ab6SJames Feist                             boost::beast::http::status::internal_server_error);
311*83ff9ab6SJames Feist                     }
312*83ff9ab6SJames Feist                 },
313*83ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
314*83ff9ab6SJames Feist                 pidConfigurationIface, "Delete");
315*83ff9ab6SJames Feist             return CreatePIDRet::del;
316*83ff9ab6SJames Feist         }
317*83ff9ab6SJames Feist 
318*83ff9ab6SJames Feist         for (auto& field : record.items())
319*83ff9ab6SJames Feist         {
320*83ff9ab6SJames Feist             if (field.key() == "Zones")
321*83ff9ab6SJames Feist             {
322*83ff9ab6SJames Feist                 if (!field.value().is_array())
323*83ff9ab6SJames Feist                 {
324*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
325*83ff9ab6SJames Feist                     messages::addMessageToErrorJson(
326*83ff9ab6SJames Feist                         response->res.jsonValue,
327*83ff9ab6SJames Feist                         messages::propertyValueFormatError(field.value(),
328*83ff9ab6SJames Feist                                                            field.key()));
329*83ff9ab6SJames Feist                     response->res.result(
330*83ff9ab6SJames Feist                         boost::beast::http::status::bad_request);
331*83ff9ab6SJames Feist                     return CreatePIDRet::fail;
332*83ff9ab6SJames Feist                 }
333*83ff9ab6SJames Feist                 std::vector<std::string> inputs;
334*83ff9ab6SJames Feist                 for (const auto& odata : field.value().items())
335*83ff9ab6SJames Feist                 {
336*83ff9ab6SJames Feist                     for (const auto& value : odata.value().items())
337*83ff9ab6SJames Feist                     {
338*83ff9ab6SJames Feist                         const std::string* path =
339*83ff9ab6SJames Feist                             value.value().get_ptr<const std::string*>();
340*83ff9ab6SJames Feist                         if (path == nullptr)
341*83ff9ab6SJames Feist                         {
342*83ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
343*83ff9ab6SJames Feist                             messages::addMessageToErrorJson(
344*83ff9ab6SJames Feist                                 response->res.jsonValue,
345*83ff9ab6SJames Feist                                 messages::propertyValueFormatError(
346*83ff9ab6SJames Feist                                     field.value().dump(), field.key()));
347*83ff9ab6SJames Feist                             response->res.result(
348*83ff9ab6SJames Feist                                 boost::beast::http::status::bad_request);
349*83ff9ab6SJames Feist                             return CreatePIDRet::fail;
350*83ff9ab6SJames Feist                         }
351*83ff9ab6SJames Feist                         std::string input;
352*83ff9ab6SJames Feist                         if (!dbus::utility::getNthStringFromPath(*path, 4,
353*83ff9ab6SJames Feist                                                                  input))
354*83ff9ab6SJames Feist                         {
355*83ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Got invalid path " << *path;
356*83ff9ab6SJames Feist                             messages::addMessageToErrorJson(
357*83ff9ab6SJames Feist                                 response->res.jsonValue,
358*83ff9ab6SJames Feist                                 messages::propertyValueFormatError(
359*83ff9ab6SJames Feist                                     field.value().dump(), field.key()));
360*83ff9ab6SJames Feist                             response->res.result(
361*83ff9ab6SJames Feist                                 boost::beast::http::status::bad_request);
362*83ff9ab6SJames Feist                             return CreatePIDRet::fail;
363*83ff9ab6SJames Feist                         }
364*83ff9ab6SJames Feist                         boost::replace_all(input, "_", " ");
365*83ff9ab6SJames Feist                         inputs.emplace_back(std::move(input));
366*83ff9ab6SJames Feist                     }
367*83ff9ab6SJames Feist                 }
368*83ff9ab6SJames Feist                 output["Zones"] = std::move(inputs);
369*83ff9ab6SJames Feist             }
370*83ff9ab6SJames Feist             else if (field.key() == "Inputs" || field.key() == "Outputs")
371*83ff9ab6SJames Feist             {
372*83ff9ab6SJames Feist                 if (!field.value().is_array())
373*83ff9ab6SJames Feist                 {
374*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
375*83ff9ab6SJames Feist                     messages::addMessageToErrorJson(
376*83ff9ab6SJames Feist                         response->res.jsonValue,
377*83ff9ab6SJames Feist                         messages::propertyValueFormatError(field.value().dump(),
378*83ff9ab6SJames Feist                                                            field.key()));
379*83ff9ab6SJames Feist                     response->res.result(
380*83ff9ab6SJames Feist                         boost::beast::http::status::bad_request);
381*83ff9ab6SJames Feist                     return CreatePIDRet::fail;
382*83ff9ab6SJames Feist                 }
383*83ff9ab6SJames Feist                 std::vector<std::string> inputs;
384*83ff9ab6SJames Feist                 for (const auto& value : field.value().items())
385*83ff9ab6SJames Feist                 {
386*83ff9ab6SJames Feist                     const std::string* sensor =
387*83ff9ab6SJames Feist                         value.value().get_ptr<const std::string*>();
388*83ff9ab6SJames Feist 
389*83ff9ab6SJames Feist                     if (sensor == nullptr)
390*83ff9ab6SJames Feist                     {
391*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type "
392*83ff9ab6SJames Feist                                          << field.value().dump();
393*83ff9ab6SJames Feist                         messages::addMessageToErrorJson(
394*83ff9ab6SJames Feist                             response->res.jsonValue,
395*83ff9ab6SJames Feist                             messages::propertyValueFormatError(
396*83ff9ab6SJames Feist                                 field.value().dump(), field.key()));
397*83ff9ab6SJames Feist                         response->res.result(
398*83ff9ab6SJames Feist                             boost::beast::http::status::bad_request);
399*83ff9ab6SJames Feist                         return CreatePIDRet::fail;
400*83ff9ab6SJames Feist                     }
401*83ff9ab6SJames Feist 
402*83ff9ab6SJames Feist                     std::string input =
403*83ff9ab6SJames Feist                         boost::replace_all_copy(*sensor, "_", " ");
404*83ff9ab6SJames Feist                     inputs.push_back(std::move(input));
405*83ff9ab6SJames Feist                     // try to find the sensor in the
406*83ff9ab6SJames Feist                     // configuration
407*83ff9ab6SJames Feist                     if (chassis.empty())
408*83ff9ab6SJames Feist                     {
409*83ff9ab6SJames Feist                         std::find_if(
410*83ff9ab6SJames Feist                             managedObj.begin(), managedObj.end(),
411*83ff9ab6SJames Feist                             [&chassis, sensor](const auto& obj) {
412*83ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
413*83ff9ab6SJames Feist                                                                 *sensor))
414*83ff9ab6SJames Feist                                 {
415*83ff9ab6SJames Feist                                     return dbus::utility::getNthStringFromPath(
416*83ff9ab6SJames Feist                                         obj.first.str, 5, chassis);
417*83ff9ab6SJames Feist                                 }
418*83ff9ab6SJames Feist                                 return false;
419*83ff9ab6SJames Feist                             });
420*83ff9ab6SJames Feist                     }
421*83ff9ab6SJames Feist                 }
422*83ff9ab6SJames Feist                 output[field.key()] = inputs;
423*83ff9ab6SJames Feist             }
424*83ff9ab6SJames Feist 
425*83ff9ab6SJames Feist             // doubles
426*83ff9ab6SJames Feist             else if (field.key() == "FFGainCoefficient" ||
427*83ff9ab6SJames Feist                      field.key() == "FFOffCoefficient" ||
428*83ff9ab6SJames Feist                      field.key() == "ICoefficient" ||
429*83ff9ab6SJames Feist                      field.key() == "ILimitMax" || field.key() == "ILimitMin" ||
430*83ff9ab6SJames Feist                      field.key() == "OutLimitMax" ||
431*83ff9ab6SJames Feist                      field.key() == "OutLimitMin" ||
432*83ff9ab6SJames Feist                      field.key() == "PCoefficient" ||
433*83ff9ab6SJames Feist                      field.key() == "SetPoint" || field.key() == "SlewNeg" ||
434*83ff9ab6SJames Feist                      field.key() == "SlewPos")
435*83ff9ab6SJames Feist             {
436*83ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
437*83ff9ab6SJames Feist                 if (ptr == nullptr)
438*83ff9ab6SJames Feist                 {
439*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
440*83ff9ab6SJames Feist                     messages::addMessageToErrorJson(
441*83ff9ab6SJames Feist                         response->res.jsonValue,
442*83ff9ab6SJames Feist                         messages::propertyValueFormatError(field.value().dump(),
443*83ff9ab6SJames Feist                                                            field.key()));
444*83ff9ab6SJames Feist                     response->res.result(
445*83ff9ab6SJames Feist                         boost::beast::http::status::bad_request);
446*83ff9ab6SJames Feist                     return CreatePIDRet::fail;
447*83ff9ab6SJames Feist                 }
448*83ff9ab6SJames Feist                 output[field.key()] = *ptr;
449*83ff9ab6SJames Feist             }
450*83ff9ab6SJames Feist 
451*83ff9ab6SJames Feist             else
452*83ff9ab6SJames Feist             {
453*83ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
454*83ff9ab6SJames Feist                 messages::addMessageToErrorJson(
455*83ff9ab6SJames Feist                     response->res.jsonValue,
456*83ff9ab6SJames Feist                     messages::propertyUnknown(field.key()));
457*83ff9ab6SJames Feist                 response->res.result(boost::beast::http::status::bad_request);
458*83ff9ab6SJames Feist                 return CreatePIDRet::fail;
459*83ff9ab6SJames Feist             }
460*83ff9ab6SJames Feist         }
461*83ff9ab6SJames Feist     }
462*83ff9ab6SJames Feist     else if (type == "FanZones")
463*83ff9ab6SJames Feist     {
464*83ff9ab6SJames Feist         if (!createNewObject && record == nullptr)
465*83ff9ab6SJames Feist         {
466*83ff9ab6SJames Feist             // delete interface
467*83ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
468*83ff9ab6SJames Feist                 [response,
469*83ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
470*83ff9ab6SJames Feist                     if (ec)
471*83ff9ab6SJames Feist                     {
472*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
473*83ff9ab6SJames Feist                                          << ec;
474*83ff9ab6SJames Feist                         response->res.result(
475*83ff9ab6SJames Feist                             boost::beast::http::status::internal_server_error);
476*83ff9ab6SJames Feist                     }
477*83ff9ab6SJames Feist                 },
478*83ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
479*83ff9ab6SJames Feist                 pidZoneConfigurationIface, "Delete");
480*83ff9ab6SJames Feist             return CreatePIDRet::del;
481*83ff9ab6SJames Feist         }
482*83ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
483*83ff9ab6SJames Feist 
484*83ff9ab6SJames Feist         for (auto& field : record.items())
485*83ff9ab6SJames Feist         {
486*83ff9ab6SJames Feist             if (field.key() == "Chassis")
487*83ff9ab6SJames Feist             {
488*83ff9ab6SJames Feist                 const std::string* chassisId = nullptr;
489*83ff9ab6SJames Feist                 for (const auto& id : field.value().items())
490*83ff9ab6SJames Feist                 {
491*83ff9ab6SJames Feist                     if (id.key() != "@odata.id")
492*83ff9ab6SJames Feist                     {
493*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << id.key();
494*83ff9ab6SJames Feist                         messages::addMessageToErrorJson(
495*83ff9ab6SJames Feist                             response->res.jsonValue,
496*83ff9ab6SJames Feist                             messages::propertyUnknown(field.key()));
497*83ff9ab6SJames Feist                         response->res.result(
498*83ff9ab6SJames Feist                             boost::beast::http::status::bad_request);
499*83ff9ab6SJames Feist                         return CreatePIDRet::fail;
500*83ff9ab6SJames Feist                     }
501*83ff9ab6SJames Feist                     chassisId = id.value().get_ptr<const std::string*>();
502*83ff9ab6SJames Feist                     if (chassisId == nullptr)
503*83ff9ab6SJames Feist                     {
504*83ff9ab6SJames Feist                         messages::addMessageToErrorJson(
505*83ff9ab6SJames Feist                             response->res.jsonValue,
506*83ff9ab6SJames Feist                             messages::createFailedMissingReqProperties(
507*83ff9ab6SJames Feist                                 field.key()));
508*83ff9ab6SJames Feist                         response->res.result(
509*83ff9ab6SJames Feist                             boost::beast::http::status::bad_request);
510*83ff9ab6SJames Feist                         return CreatePIDRet::fail;
511*83ff9ab6SJames Feist                     }
512*83ff9ab6SJames Feist                 }
513*83ff9ab6SJames Feist 
514*83ff9ab6SJames Feist                 // /refish/v1/chassis/chassis_name/
515*83ff9ab6SJames Feist                 if (!dbus::utility::getNthStringFromPath(*chassisId, 3,
516*83ff9ab6SJames Feist                                                          chassis))
517*83ff9ab6SJames Feist                 {
518*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId;
519*83ff9ab6SJames Feist                     response->res.result(
520*83ff9ab6SJames Feist                         boost::beast::http::status::bad_request);
521*83ff9ab6SJames Feist                     return CreatePIDRet::fail;
522*83ff9ab6SJames Feist                 }
523*83ff9ab6SJames Feist             }
524*83ff9ab6SJames Feist             else if (field.key() == "FailSafePercent" ||
525*83ff9ab6SJames Feist                      field.key() == "MinThermalRpm")
526*83ff9ab6SJames Feist             {
527*83ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
528*83ff9ab6SJames Feist                 if (ptr == nullptr)
529*83ff9ab6SJames Feist                 {
530*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
531*83ff9ab6SJames Feist                     messages::addMessageToErrorJson(
532*83ff9ab6SJames Feist                         response->res.jsonValue,
533*83ff9ab6SJames Feist                         messages::propertyValueFormatError(field.value().dump(),
534*83ff9ab6SJames Feist                                                            field.key()));
535*83ff9ab6SJames Feist                     response->res.result(
536*83ff9ab6SJames Feist                         boost::beast::http::status::bad_request);
537*83ff9ab6SJames Feist                     return CreatePIDRet::fail;
538*83ff9ab6SJames Feist                 }
539*83ff9ab6SJames Feist                 output[field.key()] = *ptr;
540*83ff9ab6SJames Feist             }
541*83ff9ab6SJames Feist             else
542*83ff9ab6SJames Feist             {
543*83ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
544*83ff9ab6SJames Feist                 messages::addMessageToErrorJson(
545*83ff9ab6SJames Feist                     response->res.jsonValue,
546*83ff9ab6SJames Feist                     messages::propertyUnknown(field.key()));
547*83ff9ab6SJames Feist                 response->res.result(boost::beast::http::status::bad_request);
548*83ff9ab6SJames Feist                 return CreatePIDRet::fail;
549*83ff9ab6SJames Feist             }
550*83ff9ab6SJames Feist         }
551*83ff9ab6SJames Feist     }
552*83ff9ab6SJames Feist     else
553*83ff9ab6SJames Feist     {
554*83ff9ab6SJames Feist         BMCWEB_LOG_ERROR << "Illegal Type " << type;
555*83ff9ab6SJames Feist         messages::addMessageToErrorJson(response->res.jsonValue,
556*83ff9ab6SJames Feist                                         messages::propertyUnknown(type));
557*83ff9ab6SJames Feist         response->res.result(boost::beast::http::status::bad_request);
558*83ff9ab6SJames Feist         return CreatePIDRet::fail;
559*83ff9ab6SJames Feist     }
560*83ff9ab6SJames Feist     return CreatePIDRet::patch;
561*83ff9ab6SJames Feist }
562*83ff9ab6SJames Feist 
5631abe55efSEd Tanous class Manager : public Node
5641abe55efSEd Tanous {
5659c310685SBorawski.Lukasz   public:
5665b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
5671abe55efSEd Tanous     {
5685b4aa86bSJames Feist         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc";
5699c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
5709c310685SBorawski.Lukasz         Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
5715b4aa86bSJames Feist         Node::json["Id"] = "bmc";
5729c310685SBorawski.Lukasz         Node::json["Name"] = "OpenBmc Manager";
5739c310685SBorawski.Lukasz         Node::json["Description"] = "Baseboard Management Controller";
5749c310685SBorawski.Lukasz         Node::json["PowerState"] = "On";
575ca537928SJennifer Lee         Node::json["ManagerType"] = "BMC";
5769c310685SBorawski.Lukasz         Node::json["UUID"] =
57755c7b7a2SEd Tanous             app.template getMiddleware<crow::persistent_data::Middleware>()
57855c7b7a2SEd Tanous                 .systemUuid;
5799c310685SBorawski.Lukasz         Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
580ca537928SJennifer Lee         Node::json["EthernetInterfaces"] = {
5815b4aa86bSJames Feist             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
5823ebd75f7SEd Tanous 
583a434f2bdSEd Tanous         entityPrivileges = {
584a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
585e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
586e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
587e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
588e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
589e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
5905b4aa86bSJames Feist 
5915b4aa86bSJames Feist         // default oem data
5925b4aa86bSJames Feist         nlohmann::json& oem = Node::json["Oem"];
5935b4aa86bSJames Feist         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
5945b4aa86bSJames Feist         oem["@odata.type"] = "#OemManager.Oem";
5955b4aa86bSJames Feist         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
5965b4aa86bSJames Feist         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
5975b4aa86bSJames Feist         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
5985b4aa86bSJames Feist         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
5995b4aa86bSJames Feist         oemOpenbmc["@odata.context"] =
6005b4aa86bSJames Feist             "/redfish/v1/$metadata#OemManager.OpenBmc";
6019c310685SBorawski.Lukasz     }
6029c310685SBorawski.Lukasz 
6039c310685SBorawski.Lukasz   private:
6045b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
6055b4aa86bSJames Feist     {
6065b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
6075b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
6085b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
6095b4aa86bSJames Feist                 if (ec)
6105b4aa86bSJames Feist                 {
6115b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
612f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
6135b4aa86bSJames Feist                     return;
6145b4aa86bSJames Feist                 }
6155b4aa86bSJames Feist 
6165b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
6175b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
6185b4aa86bSJames Feist                     objectMgrPaths;
6196bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
6205b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
6215b4aa86bSJames Feist                 {
6225b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
6235b4aa86bSJames Feist                     {
6246bce33bcSJames Feist                         auto findConnection =
6256bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
6266bce33bcSJames Feist                         if (findConnection != calledConnections.end())
6276bce33bcSJames Feist                         {
6286bce33bcSJames Feist                             break;
6296bce33bcSJames Feist                         }
6305b4aa86bSJames Feist                         for (const std::string& interface :
6315b4aa86bSJames Feist                              connectionGroup.second)
6325b4aa86bSJames Feist                         {
6335b4aa86bSJames Feist                             if (interface == objectManagerIface)
6345b4aa86bSJames Feist                             {
6355b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
6365b4aa86bSJames Feist                                     pathGroup.first;
6375b4aa86bSJames Feist                             }
6385b4aa86bSJames Feist                             // this list is alphabetical, so we
6395b4aa86bSJames Feist                             // should have found the objMgr by now
6405b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
6415b4aa86bSJames Feist                                 interface == pidZoneConfigurationIface)
6425b4aa86bSJames Feist                             {
6435b4aa86bSJames Feist                                 auto findObjMgr =
6445b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
6455b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
6465b4aa86bSJames Feist                                 {
6475b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
6485b4aa86bSJames Feist                                                      << "Has no Object Manager";
6495b4aa86bSJames Feist                                     continue;
6505b4aa86bSJames Feist                                 }
6516bce33bcSJames Feist 
6526bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
6536bce33bcSJames Feist 
6545b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
6555b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
6565b4aa86bSJames Feist                                 break;
6575b4aa86bSJames Feist                             }
6585b4aa86bSJames Feist                         }
6595b4aa86bSJames Feist                     }
6605b4aa86bSJames Feist                 }
6615b4aa86bSJames Feist             },
6625b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
6635b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
6645b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
6655b4aa86bSJames Feist             std::array<const char*, 3>{pidConfigurationIface,
6665b4aa86bSJames Feist                                        pidZoneConfigurationIface,
6675b4aa86bSJames Feist                                        objectManagerIface});
6685b4aa86bSJames Feist     }
6695b4aa86bSJames Feist 
67055c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
6711abe55efSEd Tanous                const std::vector<std::string>& params) override
6721abe55efSEd Tanous     {
673ca537928SJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
674ca537928SJennifer Lee         asyncResp->res.jsonValue = Node::json;
675ca537928SJennifer Lee 
6769c310685SBorawski.Lukasz         Node::json["DateTime"] = getDateTime();
67755c7b7a2SEd Tanous         res.jsonValue = Node::json;
6785b4aa86bSJames Feist 
679ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
680ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
6815b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
682ca537928SJennifer Lee                 if (ec)
683ca537928SJennifer Lee                 {
684ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
685f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
686ca537928SJennifer Lee                     return;
687ca537928SJennifer Lee                 }
688ca537928SJennifer Lee 
689ca537928SJennifer Lee                 for (auto& objpath : resp)
690ca537928SJennifer Lee                 {
691ca537928SJennifer Lee                     for (auto& interface : objpath.second)
692ca537928SJennifer Lee                     {
693ca537928SJennifer Lee                         // If interface is xyz.openbmc_project.Software.Version,
694ca537928SJennifer Lee                         // this is what we're looking for.
695ca537928SJennifer Lee                         if (interface.first ==
696ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
697ca537928SJennifer Lee                         {
698ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
699ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
700ca537928SJennifer Lee                             for (auto& property : interface.second)
701ca537928SJennifer Lee                             {
702ca537928SJennifer Lee                                 if (property.first == "Version")
703ca537928SJennifer Lee                                 {
704ca537928SJennifer Lee                                     const std::string* value =
705ca537928SJennifer Lee                                         mapbox::getPtr<const std::string>(
706ca537928SJennifer Lee                                             property.second);
707ca537928SJennifer Lee                                     if (value == nullptr)
708ca537928SJennifer Lee                                     {
709ca537928SJennifer Lee                                         continue;
710ca537928SJennifer Lee                                     }
711ca537928SJennifer Lee                                     asyncResp->res
712ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
713ca537928SJennifer Lee                                 }
714ca537928SJennifer Lee                             }
715ca537928SJennifer Lee                         }
716ca537928SJennifer Lee                     }
717ca537928SJennifer Lee                 }
718ca537928SJennifer Lee             },
719ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
720ca537928SJennifer Lee             "/xyz/openbmc_project/software",
721ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7225b4aa86bSJames Feist         getPidValues(asyncResp);
7235b4aa86bSJames Feist     }
724*83ff9ab6SJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response,
725*83ff9ab6SJames Feist                       const nlohmann::json& data)
726*83ff9ab6SJames Feist     {
727*83ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
728*83ff9ab6SJames Feist         // interface gets more traction
729*83ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
730*83ff9ab6SJames Feist             [response,
731*83ff9ab6SJames Feist              data](const boost::system::error_code ec,
732*83ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
733*83ff9ab6SJames Feist                 if (ec)
734*83ff9ab6SJames Feist                 {
735*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
736*83ff9ab6SJames Feist                     response->res.result(
737*83ff9ab6SJames Feist                         boost::beast::http::status::internal_server_error);
738*83ff9ab6SJames Feist                     return;
739*83ff9ab6SJames Feist                 }
740*83ff9ab6SJames Feist                 for (const auto& type : data.items())
741*83ff9ab6SJames Feist                 {
742*83ff9ab6SJames Feist                     if (!type.value().is_object())
743*83ff9ab6SJames Feist                     {
744*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << type.key();
745*83ff9ab6SJames Feist                         messages::addMessageToErrorJson(
746*83ff9ab6SJames Feist                             response->res.jsonValue,
747*83ff9ab6SJames Feist                             messages::propertyValueFormatError(type.value(),
748*83ff9ab6SJames Feist                                                                type.key()));
749*83ff9ab6SJames Feist                         response->res.result(
750*83ff9ab6SJames Feist                             boost::beast::http::status::bad_request);
751*83ff9ab6SJames Feist                         return;
752*83ff9ab6SJames Feist                     }
753*83ff9ab6SJames Feist                     for (const auto& record : type.value().items())
754*83ff9ab6SJames Feist                     {
755*83ff9ab6SJames Feist                         const std::string& name = record.key();
756*83ff9ab6SJames Feist                         auto pathItr =
757*83ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
758*83ff9ab6SJames Feist                                          [&name](const auto& obj) {
759*83ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
760*83ff9ab6SJames Feist                                                  obj.first.str, name);
761*83ff9ab6SJames Feist                                          });
762*83ff9ab6SJames Feist                         boost::container::flat_map<
763*83ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
764*83ff9ab6SJames Feist                             output;
765*83ff9ab6SJames Feist 
766*83ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
767*83ff9ab6SJames Feist 
768*83ff9ab6SJames Feist                         // determines if we're patching entity-manager or
769*83ff9ab6SJames Feist                         // creating a new object
770*83ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
771*83ff9ab6SJames Feist                         if (type.key() == "PidControllers" ||
772*83ff9ab6SJames Feist                             type.key() == "FanControllers")
773*83ff9ab6SJames Feist                         {
774*83ff9ab6SJames Feist                             if (!createNewObject &&
775*83ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
776*83ff9ab6SJames Feist                                     pathItr->second.end())
777*83ff9ab6SJames Feist                             {
778*83ff9ab6SJames Feist                                 createNewObject = true;
779*83ff9ab6SJames Feist                             }
780*83ff9ab6SJames Feist                         }
781*83ff9ab6SJames Feist                         else if (!createNewObject &&
782*83ff9ab6SJames Feist                                  pathItr->second.find(
783*83ff9ab6SJames Feist                                      pidZoneConfigurationIface) ==
784*83ff9ab6SJames Feist                                      pathItr->second.end())
785*83ff9ab6SJames Feist                         {
786*83ff9ab6SJames Feist                             createNewObject = true;
787*83ff9ab6SJames Feist                         }
788*83ff9ab6SJames Feist                         output["Name"] =
789*83ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
790*83ff9ab6SJames Feist 
791*83ff9ab6SJames Feist                         std::string chassis;
792*83ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
793*83ff9ab6SJames Feist                             response, type.key(), record.value(),
794*83ff9ab6SJames Feist                             pathItr->first.str, managedObj, createNewObject,
795*83ff9ab6SJames Feist                             output, chassis);
796*83ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
797*83ff9ab6SJames Feist                         {
798*83ff9ab6SJames Feist                             return;
799*83ff9ab6SJames Feist                         }
800*83ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
801*83ff9ab6SJames Feist                         {
802*83ff9ab6SJames Feist                             continue;
803*83ff9ab6SJames Feist                         }
804*83ff9ab6SJames Feist 
805*83ff9ab6SJames Feist                         if (!createNewObject)
806*83ff9ab6SJames Feist                         {
807*83ff9ab6SJames Feist                             for (const auto& property : output)
808*83ff9ab6SJames Feist                             {
809*83ff9ab6SJames Feist                                 const char* iface =
810*83ff9ab6SJames Feist                                     type.key() == "FanZones"
811*83ff9ab6SJames Feist                                         ? pidZoneConfigurationIface
812*83ff9ab6SJames Feist                                         : pidConfigurationIface;
813*83ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
814*83ff9ab6SJames Feist                                     [response,
815*83ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
816*83ff9ab6SJames Feist                                         const boost::system::error_code ec) {
817*83ff9ab6SJames Feist                                         if (ec)
818*83ff9ab6SJames Feist                                         {
819*83ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
820*83ff9ab6SJames Feist                                                 << "Error patching "
821*83ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
822*83ff9ab6SJames Feist                                             response->res.result(
823*83ff9ab6SJames Feist                                                 boost::beast::http::status::
824*83ff9ab6SJames Feist                                                     internal_server_error);
825*83ff9ab6SJames Feist                                         }
826*83ff9ab6SJames Feist                                     },
827*83ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
828*83ff9ab6SJames Feist                                     pathItr->first.str,
829*83ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
830*83ff9ab6SJames Feist                                     std::string(iface), property.first,
831*83ff9ab6SJames Feist                                     property.second);
832*83ff9ab6SJames Feist                             }
833*83ff9ab6SJames Feist                         }
834*83ff9ab6SJames Feist                         else
835*83ff9ab6SJames Feist                         {
836*83ff9ab6SJames Feist                             if (chassis.empty())
837*83ff9ab6SJames Feist                             {
838*83ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
839*83ff9ab6SJames Feist                                     << "Failed to get chassis from config";
840*83ff9ab6SJames Feist                                 response->res.result(
841*83ff9ab6SJames Feist                                     boost::beast::http::status::bad_request);
842*83ff9ab6SJames Feist                                 return;
843*83ff9ab6SJames Feist                             }
844*83ff9ab6SJames Feist 
845*83ff9ab6SJames Feist                             bool foundChassis = false;
846*83ff9ab6SJames Feist                             for (const auto& obj : managedObj)
847*83ff9ab6SJames Feist                             {
848*83ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
849*83ff9ab6SJames Feist                                                                 chassis))
850*83ff9ab6SJames Feist                                 {
851*83ff9ab6SJames Feist                                     chassis = obj.first.str;
852*83ff9ab6SJames Feist                                     foundChassis = true;
853*83ff9ab6SJames Feist                                     break;
854*83ff9ab6SJames Feist                                 }
855*83ff9ab6SJames Feist                             }
856*83ff9ab6SJames Feist                             if (!foundChassis)
857*83ff9ab6SJames Feist                             {
858*83ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
859*83ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
860*83ff9ab6SJames Feist                                 messages::addMessageToErrorJson(
861*83ff9ab6SJames Feist                                     response->res.jsonValue,
862*83ff9ab6SJames Feist                                     messages::resourceMissingAtURI(
863*83ff9ab6SJames Feist                                         "/redfish/v1/Chassis/" + chassis));
864*83ff9ab6SJames Feist                                 response->res.result(
865*83ff9ab6SJames Feist                                     boost::beast::http::status::
866*83ff9ab6SJames Feist                                         internal_server_error);
867*83ff9ab6SJames Feist                                 return;
868*83ff9ab6SJames Feist                             }
869*83ff9ab6SJames Feist 
870*83ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
871*83ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
872*83ff9ab6SJames Feist                                     if (ec)
873*83ff9ab6SJames Feist                                     {
874*83ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
875*83ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
876*83ff9ab6SJames Feist                                         response->res.result(
877*83ff9ab6SJames Feist                                             boost::beast::http::status::
878*83ff9ab6SJames Feist                                                 internal_server_error);
879*83ff9ab6SJames Feist                                     }
880*83ff9ab6SJames Feist                                 },
881*83ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
882*83ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
883*83ff9ab6SJames Feist                                 output);
884*83ff9ab6SJames Feist                         }
885*83ff9ab6SJames Feist                     }
886*83ff9ab6SJames Feist                 }
887*83ff9ab6SJames Feist             },
888*83ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
889*83ff9ab6SJames Feist             "GetManagedObjects");
890*83ff9ab6SJames Feist     }
8915b4aa86bSJames Feist 
8925b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
8935b4aa86bSJames Feist                  const std::vector<std::string>& params) override
8945b4aa86bSJames Feist     {
895*83ff9ab6SJames Feist         nlohmann::json patch;
896*83ff9ab6SJames Feist         if (!json_util::processJsonFromRequest(res, req, patch))
897*83ff9ab6SJames Feist         {
898*83ff9ab6SJames Feist             return;
899*83ff9ab6SJames Feist         }
900*83ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
901*83ff9ab6SJames Feist         for (const auto& topLevel : patch.items())
902*83ff9ab6SJames Feist         {
903*83ff9ab6SJames Feist             if (topLevel.key() == "Oem")
904*83ff9ab6SJames Feist             {
905*83ff9ab6SJames Feist                 if (!topLevel.value().is_object())
906*83ff9ab6SJames Feist                 {
907*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
908*83ff9ab6SJames Feist                     res.result(boost::beast::http::status::bad_request);
909*83ff9ab6SJames Feist                     return;
910*83ff9ab6SJames Feist                 }
911*83ff9ab6SJames Feist             }
912*83ff9ab6SJames Feist             else
913*83ff9ab6SJames Feist             {
914*83ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
915*83ff9ab6SJames Feist                 messages::addMessageToErrorJson(
916*83ff9ab6SJames Feist                     response->res.jsonValue,
917*83ff9ab6SJames Feist                     messages::propertyUnknown(topLevel.key()));
918*83ff9ab6SJames Feist                 res.result(boost::beast::http::status::bad_request);
919*83ff9ab6SJames Feist                 return;
920*83ff9ab6SJames Feist             }
921*83ff9ab6SJames Feist             for (const auto& oemLevel : topLevel.value().items())
922*83ff9ab6SJames Feist             {
923*83ff9ab6SJames Feist                 if (oemLevel.key() == "OpenBmc")
924*83ff9ab6SJames Feist                 {
925*83ff9ab6SJames Feist                     if (!oemLevel.value().is_object())
926*83ff9ab6SJames Feist                     {
927*83ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
928*83ff9ab6SJames Feist                         res.result(boost::beast::http::status::bad_request);
929*83ff9ab6SJames Feist                         return;
930*83ff9ab6SJames Feist                     }
931*83ff9ab6SJames Feist                     for (const auto& typeLevel : oemLevel.value().items())
932*83ff9ab6SJames Feist                     {
933*83ff9ab6SJames Feist 
934*83ff9ab6SJames Feist                         if (typeLevel.key() == "Fan")
935*83ff9ab6SJames Feist                         {
936*83ff9ab6SJames Feist                             if (!typeLevel.value().is_object())
937*83ff9ab6SJames Feist                             {
938*83ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR << "Bad Patch "
939*83ff9ab6SJames Feist                                                  << typeLevel.key();
940*83ff9ab6SJames Feist                                 messages::addMessageToErrorJson(
941*83ff9ab6SJames Feist                                     response->res.jsonValue,
942*83ff9ab6SJames Feist                                     messages::propertyValueFormatError(
943*83ff9ab6SJames Feist                                         typeLevel.value().dump(),
944*83ff9ab6SJames Feist                                         typeLevel.key()));
945*83ff9ab6SJames Feist                                 res.result(
946*83ff9ab6SJames Feist                                     boost::beast::http::status::bad_request);
947*83ff9ab6SJames Feist                                 return;
948*83ff9ab6SJames Feist                             }
949*83ff9ab6SJames Feist                             setPidValues(response,
950*83ff9ab6SJames Feist                                          std::move(typeLevel.value()));
951*83ff9ab6SJames Feist                         }
952*83ff9ab6SJames Feist                         else
953*83ff9ab6SJames Feist                         {
954*83ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key();
955*83ff9ab6SJames Feist                             messages::addMessageToErrorJson(
956*83ff9ab6SJames Feist                                 response->res.jsonValue,
957*83ff9ab6SJames Feist                                 messages::propertyUnknown(typeLevel.key()));
958*83ff9ab6SJames Feist                             res.result(boost::beast::http::status::bad_request);
959*83ff9ab6SJames Feist                             return;
960*83ff9ab6SJames Feist                         }
961*83ff9ab6SJames Feist                     }
962*83ff9ab6SJames Feist                 }
963*83ff9ab6SJames Feist                 else
964*83ff9ab6SJames Feist                 {
965*83ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
966*83ff9ab6SJames Feist                     messages::addMessageToErrorJson(
967*83ff9ab6SJames Feist                         response->res.jsonValue,
968*83ff9ab6SJames Feist                         messages::propertyUnknown(oemLevel.key()));
969*83ff9ab6SJames Feist                     res.result(boost::beast::http::status::bad_request);
970*83ff9ab6SJames Feist                     return;
971*83ff9ab6SJames Feist                 }
972*83ff9ab6SJames Feist             }
973*83ff9ab6SJames Feist         }
9749c310685SBorawski.Lukasz     }
9759c310685SBorawski.Lukasz 
9761abe55efSEd Tanous     std::string getDateTime() const
9771abe55efSEd Tanous     {
9789c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
9799c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
9809c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
9819c310685SBorawski.Lukasz 
9829c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
9831abe55efSEd Tanous                           std::localtime(&time)))
9841abe55efSEd Tanous         {
9859c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
9869c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
9879c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
9889c310685SBorawski.Lukasz         }
9899c310685SBorawski.Lukasz 
9909c310685SBorawski.Lukasz         return redfishDateTime;
9919c310685SBorawski.Lukasz     }
9929c310685SBorawski.Lukasz };
9939c310685SBorawski.Lukasz 
9941abe55efSEd Tanous class ManagerCollection : public Node
9951abe55efSEd Tanous {
9969c310685SBorawski.Lukasz   public:
9971abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
9981abe55efSEd Tanous     {
9999c310685SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/Managers";
10009c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
10019c310685SBorawski.Lukasz         Node::json["@odata.context"] =
10029c310685SBorawski.Lukasz             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
10039c310685SBorawski.Lukasz         Node::json["Name"] = "Manager Collection";
10049c310685SBorawski.Lukasz         Node::json["Members@odata.count"] = 1;
10055b4aa86bSJames Feist         Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}};
10063ebd75f7SEd Tanous 
1007a434f2bdSEd Tanous         entityPrivileges = {
1008a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
1009e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1010e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1011e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1012e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1013e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
10149c310685SBorawski.Lukasz     }
10159c310685SBorawski.Lukasz 
10169c310685SBorawski.Lukasz   private:
101755c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
10181abe55efSEd Tanous                const std::vector<std::string>& params) override
10191abe55efSEd Tanous     {
1020*83ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
1021*83ff9ab6SJames Feist         // because it has a duplicate entry for members
102255c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
102355c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
102455c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
102555c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
102655c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
102755c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
102855c7b7a2SEd Tanous         res.jsonValue["Members"] = {
10295b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
10309c310685SBorawski.Lukasz         res.end();
10319c310685SBorawski.Lukasz     }
10329c310685SBorawski.Lukasz };
10339c310685SBorawski.Lukasz } // namespace redfish
1034