xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision 35a62c7ca3990858cc2e04b10c4754e92c4a3e41)
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 
27583ff9ab6SJames Feist enum class CreatePIDRet
27683ff9ab6SJames Feist {
27783ff9ab6SJames Feist     fail,
27883ff9ab6SJames Feist     del,
27983ff9ab6SJames Feist     patch
28083ff9ab6SJames Feist };
28183ff9ab6SJames Feist 
28283ff9ab6SJames Feist static CreatePIDRet createPidInterface(
28383ff9ab6SJames Feist     const std::shared_ptr<AsyncResp>& response, const std::string& type,
28483ff9ab6SJames Feist     const nlohmann::json& record, const std::string& path,
28583ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
28683ff9ab6SJames Feist     boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
28783ff9ab6SJames Feist         output,
28883ff9ab6SJames Feist     std::string& chassis)
28983ff9ab6SJames Feist {
29083ff9ab6SJames Feist 
29183ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
29283ff9ab6SJames Feist     {
29383ff9ab6SJames Feist         if (createNewObject)
29483ff9ab6SJames Feist         {
29583ff9ab6SJames Feist             output["Class"] = type == "PidControllers" ? std::string("temp")
29683ff9ab6SJames Feist                                                        : std::string("fan");
29783ff9ab6SJames Feist             output["Type"] = std::string("Pid");
29883ff9ab6SJames Feist         }
29983ff9ab6SJames Feist         else if (record == nullptr)
30083ff9ab6SJames Feist         {
30183ff9ab6SJames Feist             // delete interface
30283ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
30383ff9ab6SJames Feist                 [response,
30483ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
30583ff9ab6SJames Feist                     if (ec)
30683ff9ab6SJames Feist                     {
30783ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
30883ff9ab6SJames Feist                                          << ec;
309*35a62c7cSJason M. Bills                         messages::internalError(response->res);
31083ff9ab6SJames Feist                     }
31183ff9ab6SJames Feist                 },
31283ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
31383ff9ab6SJames Feist                 pidConfigurationIface, "Delete");
31483ff9ab6SJames Feist             return CreatePIDRet::del;
31583ff9ab6SJames Feist         }
31683ff9ab6SJames Feist 
31783ff9ab6SJames Feist         for (auto& field : record.items())
31883ff9ab6SJames Feist         {
31983ff9ab6SJames Feist             if (field.key() == "Zones")
32083ff9ab6SJames Feist             {
32183ff9ab6SJames Feist                 if (!field.value().is_array())
32283ff9ab6SJames Feist                 {
32383ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
324*35a62c7cSJason M. Bills                     messages::propertyValueFormatError(
325*35a62c7cSJason M. Bills                         response->res, field.value(), field.key());
32683ff9ab6SJames Feist                     return CreatePIDRet::fail;
32783ff9ab6SJames Feist                 }
32883ff9ab6SJames Feist                 std::vector<std::string> inputs;
32983ff9ab6SJames Feist                 for (const auto& odata : field.value().items())
33083ff9ab6SJames Feist                 {
33183ff9ab6SJames Feist                     for (const auto& value : odata.value().items())
33283ff9ab6SJames Feist                     {
33383ff9ab6SJames Feist                         const std::string* path =
33483ff9ab6SJames Feist                             value.value().get_ptr<const std::string*>();
33583ff9ab6SJames Feist                         if (path == nullptr)
33683ff9ab6SJames Feist                         {
33783ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
33883ff9ab6SJames Feist                             messages::propertyValueFormatError(
339*35a62c7cSJason M. Bills                                 response->res, field.value().dump(),
340*35a62c7cSJason M. Bills                                 field.key());
34183ff9ab6SJames Feist                             return CreatePIDRet::fail;
34283ff9ab6SJames Feist                         }
34383ff9ab6SJames Feist                         std::string input;
34483ff9ab6SJames Feist                         if (!dbus::utility::getNthStringFromPath(*path, 4,
34583ff9ab6SJames Feist                                                                  input))
34683ff9ab6SJames Feist                         {
34783ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Got invalid path " << *path;
34883ff9ab6SJames Feist                             messages::propertyValueFormatError(
349*35a62c7cSJason M. Bills                                 response->res, field.value().dump(),
350*35a62c7cSJason M. Bills                                 field.key());
35183ff9ab6SJames Feist                             return CreatePIDRet::fail;
35283ff9ab6SJames Feist                         }
35383ff9ab6SJames Feist                         boost::replace_all(input, "_", " ");
35483ff9ab6SJames Feist                         inputs.emplace_back(std::move(input));
35583ff9ab6SJames Feist                     }
35683ff9ab6SJames Feist                 }
35783ff9ab6SJames Feist                 output["Zones"] = std::move(inputs);
35883ff9ab6SJames Feist             }
35983ff9ab6SJames Feist             else if (field.key() == "Inputs" || field.key() == "Outputs")
36083ff9ab6SJames Feist             {
36183ff9ab6SJames Feist                 if (!field.value().is_array())
36283ff9ab6SJames Feist                 {
36383ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
364*35a62c7cSJason M. Bills                     messages::propertyValueFormatError(
365*35a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
36683ff9ab6SJames Feist                     return CreatePIDRet::fail;
36783ff9ab6SJames Feist                 }
36883ff9ab6SJames Feist                 std::vector<std::string> inputs;
36983ff9ab6SJames Feist                 for (const auto& value : field.value().items())
37083ff9ab6SJames Feist                 {
37183ff9ab6SJames Feist                     const std::string* sensor =
37283ff9ab6SJames Feist                         value.value().get_ptr<const std::string*>();
37383ff9ab6SJames Feist 
37483ff9ab6SJames Feist                     if (sensor == nullptr)
37583ff9ab6SJames Feist                     {
37683ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type "
37783ff9ab6SJames Feist                                          << field.value().dump();
37883ff9ab6SJames Feist                         messages::propertyValueFormatError(
379*35a62c7cSJason M. Bills                             response->res, field.value().dump(), field.key());
38083ff9ab6SJames Feist                         return CreatePIDRet::fail;
38183ff9ab6SJames Feist                     }
38283ff9ab6SJames Feist 
38383ff9ab6SJames Feist                     std::string input =
38483ff9ab6SJames Feist                         boost::replace_all_copy(*sensor, "_", " ");
38583ff9ab6SJames Feist                     inputs.push_back(std::move(input));
38683ff9ab6SJames Feist                     // try to find the sensor in the
38783ff9ab6SJames Feist                     // configuration
38883ff9ab6SJames Feist                     if (chassis.empty())
38983ff9ab6SJames Feist                     {
39083ff9ab6SJames Feist                         std::find_if(
39183ff9ab6SJames Feist                             managedObj.begin(), managedObj.end(),
39283ff9ab6SJames Feist                             [&chassis, sensor](const auto& obj) {
39383ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
39483ff9ab6SJames Feist                                                                 *sensor))
39583ff9ab6SJames Feist                                 {
39683ff9ab6SJames Feist                                     return dbus::utility::getNthStringFromPath(
39783ff9ab6SJames Feist                                         obj.first.str, 5, chassis);
39883ff9ab6SJames Feist                                 }
39983ff9ab6SJames Feist                                 return false;
40083ff9ab6SJames Feist                             });
40183ff9ab6SJames Feist                     }
40283ff9ab6SJames Feist                 }
40383ff9ab6SJames Feist                 output[field.key()] = inputs;
40483ff9ab6SJames Feist             }
40583ff9ab6SJames Feist 
40683ff9ab6SJames Feist             // doubles
40783ff9ab6SJames Feist             else if (field.key() == "FFGainCoefficient" ||
40883ff9ab6SJames Feist                      field.key() == "FFOffCoefficient" ||
40983ff9ab6SJames Feist                      field.key() == "ICoefficient" ||
41083ff9ab6SJames Feist                      field.key() == "ILimitMax" || field.key() == "ILimitMin" ||
41183ff9ab6SJames Feist                      field.key() == "OutLimitMax" ||
41283ff9ab6SJames Feist                      field.key() == "OutLimitMin" ||
41383ff9ab6SJames Feist                      field.key() == "PCoefficient" ||
41483ff9ab6SJames Feist                      field.key() == "SetPoint" || field.key() == "SlewNeg" ||
41583ff9ab6SJames Feist                      field.key() == "SlewPos")
41683ff9ab6SJames Feist             {
41783ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
41883ff9ab6SJames Feist                 if (ptr == nullptr)
41983ff9ab6SJames Feist                 {
42083ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
421*35a62c7cSJason M. Bills                     messages::propertyValueFormatError(
422*35a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
42383ff9ab6SJames Feist                     return CreatePIDRet::fail;
42483ff9ab6SJames Feist                 }
42583ff9ab6SJames Feist                 output[field.key()] = *ptr;
42683ff9ab6SJames Feist             }
42783ff9ab6SJames Feist 
42883ff9ab6SJames Feist             else
42983ff9ab6SJames Feist             {
43083ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
431*35a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
43283ff9ab6SJames Feist                 return CreatePIDRet::fail;
43383ff9ab6SJames Feist             }
43483ff9ab6SJames Feist         }
43583ff9ab6SJames Feist     }
43683ff9ab6SJames Feist     else if (type == "FanZones")
43783ff9ab6SJames Feist     {
43883ff9ab6SJames Feist         if (!createNewObject && record == nullptr)
43983ff9ab6SJames Feist         {
44083ff9ab6SJames Feist             // delete interface
44183ff9ab6SJames Feist             crow::connections::systemBus->async_method_call(
44283ff9ab6SJames Feist                 [response,
44383ff9ab6SJames Feist                  path{std::string(path)}](const boost::system::error_code ec) {
44483ff9ab6SJames Feist                     if (ec)
44583ff9ab6SJames Feist                     {
44683ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Error patching " << path << ": "
44783ff9ab6SJames Feist                                          << ec;
448*35a62c7cSJason M. Bills                         messages::internalError(response->res);
44983ff9ab6SJames Feist                     }
45083ff9ab6SJames Feist                 },
45183ff9ab6SJames Feist                 "xyz.openbmc_project.EntityManager", path,
45283ff9ab6SJames Feist                 pidZoneConfigurationIface, "Delete");
45383ff9ab6SJames Feist             return CreatePIDRet::del;
45483ff9ab6SJames Feist         }
45583ff9ab6SJames Feist         output["Type"] = std::string("Pid.Zone");
45683ff9ab6SJames Feist 
45783ff9ab6SJames Feist         for (auto& field : record.items())
45883ff9ab6SJames Feist         {
45983ff9ab6SJames Feist             if (field.key() == "Chassis")
46083ff9ab6SJames Feist             {
46183ff9ab6SJames Feist                 const std::string* chassisId = nullptr;
46283ff9ab6SJames Feist                 for (const auto& id : field.value().items())
46383ff9ab6SJames Feist                 {
46483ff9ab6SJames Feist                     if (id.key() != "@odata.id")
46583ff9ab6SJames Feist                     {
46683ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << id.key();
467*35a62c7cSJason M. Bills                         messages::propertyUnknown(response->res, field.key());
46883ff9ab6SJames Feist                         return CreatePIDRet::fail;
46983ff9ab6SJames Feist                     }
47083ff9ab6SJames Feist                     chassisId = id.value().get_ptr<const std::string*>();
47183ff9ab6SJames Feist                     if (chassisId == nullptr)
47283ff9ab6SJames Feist                     {
47383ff9ab6SJames Feist                         messages::createFailedMissingReqProperties(
474*35a62c7cSJason M. Bills                             response->res, field.key());
47583ff9ab6SJames Feist                         return CreatePIDRet::fail;
47683ff9ab6SJames Feist                     }
47783ff9ab6SJames Feist                 }
47883ff9ab6SJames Feist 
47983ff9ab6SJames Feist                 // /refish/v1/chassis/chassis_name/
48083ff9ab6SJames Feist                 if (!dbus::utility::getNthStringFromPath(*chassisId, 3,
48183ff9ab6SJames Feist                                                          chassis))
48283ff9ab6SJames Feist                 {
48383ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId;
484*35a62c7cSJason M. Bills                     messages::invalidObject(response->res, *chassisId);
48583ff9ab6SJames Feist                     return CreatePIDRet::fail;
48683ff9ab6SJames Feist                 }
48783ff9ab6SJames Feist             }
48883ff9ab6SJames Feist             else if (field.key() == "FailSafePercent" ||
48983ff9ab6SJames Feist                      field.key() == "MinThermalRpm")
49083ff9ab6SJames Feist             {
49183ff9ab6SJames Feist                 const double* ptr = field.value().get_ptr<const double*>();
49283ff9ab6SJames Feist                 if (ptr == nullptr)
49383ff9ab6SJames Feist                 {
49483ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
495*35a62c7cSJason M. Bills                     messages::propertyValueFormatError(
496*35a62c7cSJason M. Bills                         response->res, field.value().dump(), field.key());
49783ff9ab6SJames Feist                     return CreatePIDRet::fail;
49883ff9ab6SJames Feist                 }
49983ff9ab6SJames Feist                 output[field.key()] = *ptr;
50083ff9ab6SJames Feist             }
50183ff9ab6SJames Feist             else
50283ff9ab6SJames Feist             {
50383ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Illegal Type " << field.key();
504*35a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, field.key());
50583ff9ab6SJames Feist                 return CreatePIDRet::fail;
50683ff9ab6SJames Feist             }
50783ff9ab6SJames Feist         }
50883ff9ab6SJames Feist     }
50983ff9ab6SJames Feist     else
51083ff9ab6SJames Feist     {
51183ff9ab6SJames Feist         BMCWEB_LOG_ERROR << "Illegal Type " << type;
512*35a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
51383ff9ab6SJames Feist         return CreatePIDRet::fail;
51483ff9ab6SJames Feist     }
51583ff9ab6SJames Feist     return CreatePIDRet::patch;
51683ff9ab6SJames Feist }
51783ff9ab6SJames Feist 
5181abe55efSEd Tanous class Manager : public Node
5191abe55efSEd Tanous {
5209c310685SBorawski.Lukasz   public:
5215b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
5221abe55efSEd Tanous     {
5235b4aa86bSJames Feist         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc";
5249c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
5259c310685SBorawski.Lukasz         Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
5265b4aa86bSJames Feist         Node::json["Id"] = "bmc";
5279c310685SBorawski.Lukasz         Node::json["Name"] = "OpenBmc Manager";
5289c310685SBorawski.Lukasz         Node::json["Description"] = "Baseboard Management Controller";
5299c310685SBorawski.Lukasz         Node::json["PowerState"] = "On";
530ca537928SJennifer Lee         Node::json["ManagerType"] = "BMC";
5319c310685SBorawski.Lukasz         Node::json["UUID"] =
53255c7b7a2SEd Tanous             app.template getMiddleware<crow::persistent_data::Middleware>()
53355c7b7a2SEd Tanous                 .systemUuid;
5349c310685SBorawski.Lukasz         Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
535ca537928SJennifer Lee         Node::json["EthernetInterfaces"] = {
5365b4aa86bSJames Feist             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
5373ebd75f7SEd Tanous 
538a434f2bdSEd Tanous         entityPrivileges = {
539a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
540e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
541e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
542e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
543e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
544e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
5455b4aa86bSJames Feist 
5465b4aa86bSJames Feist         // default oem data
5475b4aa86bSJames Feist         nlohmann::json& oem = Node::json["Oem"];
5485b4aa86bSJames Feist         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
5495b4aa86bSJames Feist         oem["@odata.type"] = "#OemManager.Oem";
5505b4aa86bSJames Feist         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
5515b4aa86bSJames Feist         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
5525b4aa86bSJames Feist         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
5535b4aa86bSJames Feist         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
5545b4aa86bSJames Feist         oemOpenbmc["@odata.context"] =
5555b4aa86bSJames Feist             "/redfish/v1/$metadata#OemManager.OpenBmc";
5569c310685SBorawski.Lukasz     }
5579c310685SBorawski.Lukasz 
5589c310685SBorawski.Lukasz   private:
5595b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
5605b4aa86bSJames Feist     {
5615b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
5625b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
5635b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
5645b4aa86bSJames Feist                 if (ec)
5655b4aa86bSJames Feist                 {
5665b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
567f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
5685b4aa86bSJames Feist                     return;
5695b4aa86bSJames Feist                 }
5705b4aa86bSJames Feist 
5715b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
5725b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
5735b4aa86bSJames Feist                     objectMgrPaths;
5746bce33bcSJames Feist                 boost::container::flat_set<std::string> calledConnections;
5755b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
5765b4aa86bSJames Feist                 {
5775b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
5785b4aa86bSJames Feist                     {
5796bce33bcSJames Feist                         auto findConnection =
5806bce33bcSJames Feist                             calledConnections.find(connectionGroup.first);
5816bce33bcSJames Feist                         if (findConnection != calledConnections.end())
5826bce33bcSJames Feist                         {
5836bce33bcSJames Feist                             break;
5846bce33bcSJames Feist                         }
5855b4aa86bSJames Feist                         for (const std::string& interface :
5865b4aa86bSJames Feist                              connectionGroup.second)
5875b4aa86bSJames Feist                         {
5885b4aa86bSJames Feist                             if (interface == objectManagerIface)
5895b4aa86bSJames Feist                             {
5905b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
5915b4aa86bSJames Feist                                     pathGroup.first;
5925b4aa86bSJames Feist                             }
5935b4aa86bSJames Feist                             // this list is alphabetical, so we
5945b4aa86bSJames Feist                             // should have found the objMgr by now
5955b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
5965b4aa86bSJames Feist                                 interface == pidZoneConfigurationIface)
5975b4aa86bSJames Feist                             {
5985b4aa86bSJames Feist                                 auto findObjMgr =
5995b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
6005b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
6015b4aa86bSJames Feist                                 {
6025b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
6035b4aa86bSJames Feist                                                      << "Has no Object Manager";
6045b4aa86bSJames Feist                                     continue;
6055b4aa86bSJames Feist                                 }
6066bce33bcSJames Feist 
6076bce33bcSJames Feist                                 calledConnections.insert(connectionGroup.first);
6086bce33bcSJames Feist 
6095b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
6105b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
6115b4aa86bSJames Feist                                 break;
6125b4aa86bSJames Feist                             }
6135b4aa86bSJames Feist                         }
6145b4aa86bSJames Feist                     }
6155b4aa86bSJames Feist                 }
6165b4aa86bSJames Feist             },
6175b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
6185b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
6195b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
6205b4aa86bSJames Feist             std::array<const char*, 3>{pidConfigurationIface,
6215b4aa86bSJames Feist                                        pidZoneConfigurationIface,
6225b4aa86bSJames Feist                                        objectManagerIface});
6235b4aa86bSJames Feist     }
6245b4aa86bSJames Feist 
62555c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
6261abe55efSEd Tanous                const std::vector<std::string>& params) override
6271abe55efSEd Tanous     {
628ca537928SJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
629ca537928SJennifer Lee         asyncResp->res.jsonValue = Node::json;
630ca537928SJennifer Lee 
6319c310685SBorawski.Lukasz         Node::json["DateTime"] = getDateTime();
63255c7b7a2SEd Tanous         res.jsonValue = Node::json;
6335b4aa86bSJames Feist 
634ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
635ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
6365b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
637ca537928SJennifer Lee                 if (ec)
638ca537928SJennifer Lee                 {
639ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
640f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
641ca537928SJennifer Lee                     return;
642ca537928SJennifer Lee                 }
643ca537928SJennifer Lee 
644ca537928SJennifer Lee                 for (auto& objpath : resp)
645ca537928SJennifer Lee                 {
646ca537928SJennifer Lee                     for (auto& interface : objpath.second)
647ca537928SJennifer Lee                     {
648ca537928SJennifer Lee                         // If interface is xyz.openbmc_project.Software.Version,
649ca537928SJennifer Lee                         // this is what we're looking for.
650ca537928SJennifer Lee                         if (interface.first ==
651ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
652ca537928SJennifer Lee                         {
653ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
654ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
655ca537928SJennifer Lee                             for (auto& property : interface.second)
656ca537928SJennifer Lee                             {
657ca537928SJennifer Lee                                 if (property.first == "Version")
658ca537928SJennifer Lee                                 {
659ca537928SJennifer Lee                                     const std::string* value =
660ca537928SJennifer Lee                                         mapbox::getPtr<const std::string>(
661ca537928SJennifer Lee                                             property.second);
662ca537928SJennifer Lee                                     if (value == nullptr)
663ca537928SJennifer Lee                                     {
664ca537928SJennifer Lee                                         continue;
665ca537928SJennifer Lee                                     }
666ca537928SJennifer Lee                                     asyncResp->res
667ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
668ca537928SJennifer Lee                                 }
669ca537928SJennifer Lee                             }
670ca537928SJennifer Lee                         }
671ca537928SJennifer Lee                     }
672ca537928SJennifer Lee                 }
673ca537928SJennifer Lee             },
674ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
675ca537928SJennifer Lee             "/xyz/openbmc_project/software",
676ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
6775b4aa86bSJames Feist         getPidValues(asyncResp);
6785b4aa86bSJames Feist     }
67983ff9ab6SJames Feist     void setPidValues(std::shared_ptr<AsyncResp> response,
68083ff9ab6SJames Feist                       const nlohmann::json& data)
68183ff9ab6SJames Feist     {
68283ff9ab6SJames Feist         // todo(james): might make sense to do a mapper call here if this
68383ff9ab6SJames Feist         // interface gets more traction
68483ff9ab6SJames Feist         crow::connections::systemBus->async_method_call(
68583ff9ab6SJames Feist             [response,
68683ff9ab6SJames Feist              data](const boost::system::error_code ec,
68783ff9ab6SJames Feist                    const dbus::utility::ManagedObjectType& managedObj) {
68883ff9ab6SJames Feist                 if (ec)
68983ff9ab6SJames Feist                 {
69083ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
691*35a62c7cSJason M. Bills                     messages::internalError(response->res);
69283ff9ab6SJames Feist                     return;
69383ff9ab6SJames Feist                 }
69483ff9ab6SJames Feist                 for (const auto& type : data.items())
69583ff9ab6SJames Feist                 {
69683ff9ab6SJames Feist                     if (!type.value().is_object())
69783ff9ab6SJames Feist                     {
69883ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Illegal Type " << type.key();
699*35a62c7cSJason M. Bills                         messages::propertyValueFormatError(
700*35a62c7cSJason M. Bills                             response->res, type.value(), type.key());
70183ff9ab6SJames Feist                         return;
70283ff9ab6SJames Feist                     }
70383ff9ab6SJames Feist                     for (const auto& record : type.value().items())
70483ff9ab6SJames Feist                     {
70583ff9ab6SJames Feist                         const std::string& name = record.key();
70683ff9ab6SJames Feist                         auto pathItr =
70783ff9ab6SJames Feist                             std::find_if(managedObj.begin(), managedObj.end(),
70883ff9ab6SJames Feist                                          [&name](const auto& obj) {
70983ff9ab6SJames Feist                                              return boost::algorithm::ends_with(
71083ff9ab6SJames Feist                                                  obj.first.str, name);
71183ff9ab6SJames Feist                                          });
71283ff9ab6SJames Feist                         boost::container::flat_map<
71383ff9ab6SJames Feist                             std::string, dbus::utility::DbusVariantType>
71483ff9ab6SJames Feist                             output;
71583ff9ab6SJames Feist 
71683ff9ab6SJames Feist                         output.reserve(16); // The pid interface length
71783ff9ab6SJames Feist 
71883ff9ab6SJames Feist                         // determines if we're patching entity-manager or
71983ff9ab6SJames Feist                         // creating a new object
72083ff9ab6SJames Feist                         bool createNewObject = (pathItr == managedObj.end());
72183ff9ab6SJames Feist                         if (type.key() == "PidControllers" ||
72283ff9ab6SJames Feist                             type.key() == "FanControllers")
72383ff9ab6SJames Feist                         {
72483ff9ab6SJames Feist                             if (!createNewObject &&
72583ff9ab6SJames Feist                                 pathItr->second.find(pidConfigurationIface) ==
72683ff9ab6SJames Feist                                     pathItr->second.end())
72783ff9ab6SJames Feist                             {
72883ff9ab6SJames Feist                                 createNewObject = true;
72983ff9ab6SJames Feist                             }
73083ff9ab6SJames Feist                         }
73183ff9ab6SJames Feist                         else if (!createNewObject &&
73283ff9ab6SJames Feist                                  pathItr->second.find(
73383ff9ab6SJames Feist                                      pidZoneConfigurationIface) ==
73483ff9ab6SJames Feist                                      pathItr->second.end())
73583ff9ab6SJames Feist                         {
73683ff9ab6SJames Feist                             createNewObject = true;
73783ff9ab6SJames Feist                         }
73883ff9ab6SJames Feist                         output["Name"] =
73983ff9ab6SJames Feist                             boost::replace_all_copy(name, "_", " ");
74083ff9ab6SJames Feist 
74183ff9ab6SJames Feist                         std::string chassis;
74283ff9ab6SJames Feist                         CreatePIDRet ret = createPidInterface(
74383ff9ab6SJames Feist                             response, type.key(), record.value(),
74483ff9ab6SJames Feist                             pathItr->first.str, managedObj, createNewObject,
74583ff9ab6SJames Feist                             output, chassis);
74683ff9ab6SJames Feist                         if (ret == CreatePIDRet::fail)
74783ff9ab6SJames Feist                         {
74883ff9ab6SJames Feist                             return;
74983ff9ab6SJames Feist                         }
75083ff9ab6SJames Feist                         else if (ret == CreatePIDRet::del)
75183ff9ab6SJames Feist                         {
75283ff9ab6SJames Feist                             continue;
75383ff9ab6SJames Feist                         }
75483ff9ab6SJames Feist 
75583ff9ab6SJames Feist                         if (!createNewObject)
75683ff9ab6SJames Feist                         {
75783ff9ab6SJames Feist                             for (const auto& property : output)
75883ff9ab6SJames Feist                             {
75983ff9ab6SJames Feist                                 const char* iface =
76083ff9ab6SJames Feist                                     type.key() == "FanZones"
76183ff9ab6SJames Feist                                         ? pidZoneConfigurationIface
76283ff9ab6SJames Feist                                         : pidConfigurationIface;
76383ff9ab6SJames Feist                                 crow::connections::systemBus->async_method_call(
76483ff9ab6SJames Feist                                     [response,
76583ff9ab6SJames Feist                                      propertyName{std::string(property.first)}](
76683ff9ab6SJames Feist                                         const boost::system::error_code ec) {
76783ff9ab6SJames Feist                                         if (ec)
76883ff9ab6SJames Feist                                         {
76983ff9ab6SJames Feist                                             BMCWEB_LOG_ERROR
77083ff9ab6SJames Feist                                                 << "Error patching "
77183ff9ab6SJames Feist                                                 << propertyName << ": " << ec;
772*35a62c7cSJason M. Bills                                             messages::internalError(
773*35a62c7cSJason M. Bills                                                 response->res);
77483ff9ab6SJames Feist                                         }
77583ff9ab6SJames Feist                                     },
77683ff9ab6SJames Feist                                     "xyz.openbmc_project.EntityManager",
77783ff9ab6SJames Feist                                     pathItr->first.str,
77883ff9ab6SJames Feist                                     "org.freedesktop.DBus.Properties", "Set",
77983ff9ab6SJames Feist                                     std::string(iface), property.first,
78083ff9ab6SJames Feist                                     property.second);
78183ff9ab6SJames Feist                             }
78283ff9ab6SJames Feist                         }
78383ff9ab6SJames Feist                         else
78483ff9ab6SJames Feist                         {
78583ff9ab6SJames Feist                             if (chassis.empty())
78683ff9ab6SJames Feist                             {
78783ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
78883ff9ab6SJames Feist                                     << "Failed to get chassis from config";
789*35a62c7cSJason M. Bills                                 messages::invalidObject(response->res, name);
79083ff9ab6SJames Feist                                 return;
79183ff9ab6SJames Feist                             }
79283ff9ab6SJames Feist 
79383ff9ab6SJames Feist                             bool foundChassis = false;
79483ff9ab6SJames Feist                             for (const auto& obj : managedObj)
79583ff9ab6SJames Feist                             {
79683ff9ab6SJames Feist                                 if (boost::algorithm::ends_with(obj.first.str,
79783ff9ab6SJames Feist                                                                 chassis))
79883ff9ab6SJames Feist                                 {
79983ff9ab6SJames Feist                                     chassis = obj.first.str;
80083ff9ab6SJames Feist                                     foundChassis = true;
80183ff9ab6SJames Feist                                     break;
80283ff9ab6SJames Feist                                 }
80383ff9ab6SJames Feist                             }
80483ff9ab6SJames Feist                             if (!foundChassis)
80583ff9ab6SJames Feist                             {
80683ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR
80783ff9ab6SJames Feist                                     << "Failed to find chassis on dbus";
80883ff9ab6SJames Feist                                 messages::resourceMissingAtURI(
809*35a62c7cSJason M. Bills                                     response->res,
810*35a62c7cSJason M. Bills                                     "/redfish/v1/Chassis/" + chassis);
81183ff9ab6SJames Feist                                 return;
81283ff9ab6SJames Feist                             }
81383ff9ab6SJames Feist 
81483ff9ab6SJames Feist                             crow::connections::systemBus->async_method_call(
81583ff9ab6SJames Feist                                 [response](const boost::system::error_code ec) {
81683ff9ab6SJames Feist                                     if (ec)
81783ff9ab6SJames Feist                                     {
81883ff9ab6SJames Feist                                         BMCWEB_LOG_ERROR
81983ff9ab6SJames Feist                                             << "Error Adding Pid Object " << ec;
820*35a62c7cSJason M. Bills                                         messages::internalError(response->res);
82183ff9ab6SJames Feist                                     }
82283ff9ab6SJames Feist                                 },
82383ff9ab6SJames Feist                                 "xyz.openbmc_project.EntityManager", chassis,
82483ff9ab6SJames Feist                                 "xyz.openbmc_project.AddObject", "AddObject",
82583ff9ab6SJames Feist                                 output);
82683ff9ab6SJames Feist                         }
82783ff9ab6SJames Feist                     }
82883ff9ab6SJames Feist                 }
82983ff9ab6SJames Feist             },
83083ff9ab6SJames Feist             "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
83183ff9ab6SJames Feist             "GetManagedObjects");
83283ff9ab6SJames Feist     }
8335b4aa86bSJames Feist 
8345b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
8355b4aa86bSJames Feist                  const std::vector<std::string>& params) override
8365b4aa86bSJames Feist     {
83783ff9ab6SJames Feist         nlohmann::json patch;
83883ff9ab6SJames Feist         if (!json_util::processJsonFromRequest(res, req, patch))
83983ff9ab6SJames Feist         {
84083ff9ab6SJames Feist             return;
84183ff9ab6SJames Feist         }
84283ff9ab6SJames Feist         std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
84383ff9ab6SJames Feist         for (const auto& topLevel : patch.items())
84483ff9ab6SJames Feist         {
84583ff9ab6SJames Feist             if (topLevel.key() == "Oem")
84683ff9ab6SJames Feist             {
84783ff9ab6SJames Feist                 if (!topLevel.value().is_object())
84883ff9ab6SJames Feist                 {
84983ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
850*35a62c7cSJason M. Bills                     messages::propertyValueFormatError(
851*35a62c7cSJason M. Bills                         response->res, topLevel.key(), "OemManager.Oem");
85283ff9ab6SJames Feist                     return;
85383ff9ab6SJames Feist                 }
85483ff9ab6SJames Feist             }
85583ff9ab6SJames Feist             else
85683ff9ab6SJames Feist             {
85783ff9ab6SJames Feist                 BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key();
858*35a62c7cSJason M. Bills                 messages::propertyUnknown(response->res, topLevel.key());
85983ff9ab6SJames Feist                 return;
86083ff9ab6SJames Feist             }
86183ff9ab6SJames Feist             for (const auto& oemLevel : topLevel.value().items())
86283ff9ab6SJames Feist             {
86383ff9ab6SJames Feist                 if (oemLevel.key() == "OpenBmc")
86483ff9ab6SJames Feist                 {
86583ff9ab6SJames Feist                     if (!oemLevel.value().is_object())
86683ff9ab6SJames Feist                     {
86783ff9ab6SJames Feist                         BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
868*35a62c7cSJason M. Bills                         messages::propertyValueFormatError(
869*35a62c7cSJason M. Bills                             response->res, topLevel.key(),
870*35a62c7cSJason M. Bills                             "OemManager.OpenBmc");
87183ff9ab6SJames Feist                         return;
87283ff9ab6SJames Feist                     }
87383ff9ab6SJames Feist                     for (const auto& typeLevel : oemLevel.value().items())
87483ff9ab6SJames Feist                     {
87583ff9ab6SJames Feist 
87683ff9ab6SJames Feist                         if (typeLevel.key() == "Fan")
87783ff9ab6SJames Feist                         {
87883ff9ab6SJames Feist                             if (!typeLevel.value().is_object())
87983ff9ab6SJames Feist                             {
88083ff9ab6SJames Feist                                 BMCWEB_LOG_ERROR << "Bad Patch "
88183ff9ab6SJames Feist                                                  << typeLevel.key();
88283ff9ab6SJames Feist                                 messages::propertyValueFormatError(
883*35a62c7cSJason M. Bills                                     response->res, typeLevel.value().dump(),
884*35a62c7cSJason M. Bills                                     typeLevel.key());
88583ff9ab6SJames Feist                                 return;
88683ff9ab6SJames Feist                             }
88783ff9ab6SJames Feist                             setPidValues(response,
88883ff9ab6SJames Feist                                          std::move(typeLevel.value()));
88983ff9ab6SJames Feist                         }
89083ff9ab6SJames Feist                         else
89183ff9ab6SJames Feist                         {
89283ff9ab6SJames Feist                             BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key();
893*35a62c7cSJason M. Bills                             messages::propertyUnknown(response->res,
894*35a62c7cSJason M. Bills                                                       typeLevel.key());
89583ff9ab6SJames Feist                             return;
89683ff9ab6SJames Feist                         }
89783ff9ab6SJames Feist                     }
89883ff9ab6SJames Feist                 }
89983ff9ab6SJames Feist                 else
90083ff9ab6SJames Feist                 {
90183ff9ab6SJames Feist                     BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key();
902*35a62c7cSJason M. Bills                     messages::propertyUnknown(response->res, oemLevel.key());
90383ff9ab6SJames Feist                     return;
90483ff9ab6SJames Feist                 }
90583ff9ab6SJames Feist             }
90683ff9ab6SJames Feist         }
9079c310685SBorawski.Lukasz     }
9089c310685SBorawski.Lukasz 
9091abe55efSEd Tanous     std::string getDateTime() const
9101abe55efSEd Tanous     {
9119c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
9129c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
9139c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
9149c310685SBorawski.Lukasz 
9159c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
9161abe55efSEd Tanous                           std::localtime(&time)))
9171abe55efSEd Tanous         {
9189c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
9199c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
9209c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
9219c310685SBorawski.Lukasz         }
9229c310685SBorawski.Lukasz 
9239c310685SBorawski.Lukasz         return redfishDateTime;
9249c310685SBorawski.Lukasz     }
9259c310685SBorawski.Lukasz };
9269c310685SBorawski.Lukasz 
9271abe55efSEd Tanous class ManagerCollection : public Node
9281abe55efSEd Tanous {
9299c310685SBorawski.Lukasz   public:
9301abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
9311abe55efSEd Tanous     {
9329c310685SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/Managers";
9339c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
9349c310685SBorawski.Lukasz         Node::json["@odata.context"] =
9359c310685SBorawski.Lukasz             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
9369c310685SBorawski.Lukasz         Node::json["Name"] = "Manager Collection";
9379c310685SBorawski.Lukasz         Node::json["Members@odata.count"] = 1;
9385b4aa86bSJames Feist         Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}};
9393ebd75f7SEd Tanous 
940a434f2bdSEd Tanous         entityPrivileges = {
941a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
942e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
943e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
944e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
945e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
946e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
9479c310685SBorawski.Lukasz     }
9489c310685SBorawski.Lukasz 
9499c310685SBorawski.Lukasz   private:
95055c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
9511abe55efSEd Tanous                const std::vector<std::string>& params) override
9521abe55efSEd Tanous     {
95383ff9ab6SJames Feist         // Collections don't include the static data added by SubRoute
95483ff9ab6SJames Feist         // because it has a duplicate entry for members
95555c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
95655c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
95755c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
95855c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
95955c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
96055c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
96155c7b7a2SEd Tanous         res.jsonValue["Members"] = {
9625b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
9639c310685SBorawski.Lukasz         res.end();
9649c310685SBorawski.Lukasz     }
9659c310685SBorawski.Lukasz };
9669c310685SBorawski.Lukasz } // namespace redfish
967