xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision 5b4aa86b670e72d4d6132561bd67f87b1419bb42)
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 
20*5b4aa86bSJames Feist #include <boost/algorithm/string/replace.hpp>
21*5b4aa86bSJames Feist #include <dbus_utility.hpp>
22*5b4aa86bSJames Feist 
231abe55efSEd Tanous namespace redfish
241abe55efSEd Tanous {
25*5b4aa86bSJames Feist static constexpr const char* objectManagerIface =
26*5b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
27*5b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
28*5b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
29*5b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
30*5b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
319c310685SBorawski.Lukasz 
32*5b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection,
33*5b4aa86bSJames Feist                              const std::string& path,
34*5b4aa86bSJames Feist                              std::shared_ptr<AsyncResp> asyncResp)
35*5b4aa86bSJames Feist {
36*5b4aa86bSJames Feist 
37*5b4aa86bSJames Feist     crow::connections::systemBus->async_method_call(
38*5b4aa86bSJames Feist         [asyncResp](const boost::system::error_code ec,
39*5b4aa86bSJames Feist                     const dbus::utility::ManagedObjectType& managedObj) {
40*5b4aa86bSJames Feist             if (ec)
41*5b4aa86bSJames Feist             {
42*5b4aa86bSJames Feist                 BMCWEB_LOG_ERROR << ec;
43*5b4aa86bSJames Feist                 asyncResp->res.result(
44*5b4aa86bSJames Feist                     boost::beast::http::status::internal_server_error);
45*5b4aa86bSJames Feist                 asyncResp->res.jsonValue.clear();
46*5b4aa86bSJames Feist                 return;
47*5b4aa86bSJames Feist             }
48*5b4aa86bSJames Feist             nlohmann::json& configRoot =
49*5b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
50*5b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
51*5b4aa86bSJames Feist             fans["@odata.type"] = "#OemManager.FanControllers";
52*5b4aa86bSJames Feist             fans["@odata.context"] =
53*5b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanControllers";
54*5b4aa86bSJames Feist             fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
55*5b4aa86bSJames Feist                                 "Fan/FanControllers";
56*5b4aa86bSJames Feist 
57*5b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
58*5b4aa86bSJames Feist             pids["@odata.type"] = "#OemManager.PidControllers";
59*5b4aa86bSJames Feist             pids["@odata.context"] =
60*5b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.PidControllers";
61*5b4aa86bSJames Feist             pids["@odata.id"] =
62*5b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
63*5b4aa86bSJames Feist 
64*5b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
65*5b4aa86bSJames Feist             zones["@odata.id"] =
66*5b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
67*5b4aa86bSJames Feist             zones["@odata.type"] = "#OemManager.FanZones";
68*5b4aa86bSJames Feist             zones["@odata.context"] =
69*5b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.FanZones";
70*5b4aa86bSJames Feist             configRoot["@odata.id"] =
71*5b4aa86bSJames Feist                 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
72*5b4aa86bSJames Feist             configRoot["@odata.type"] = "#OemManager.Fan";
73*5b4aa86bSJames Feist             configRoot["@odata.context"] =
74*5b4aa86bSJames Feist                 "/redfish/v1/$metadata#OemManager.Fan";
75*5b4aa86bSJames Feist 
76*5b4aa86bSJames Feist             bool propertyError = false;
77*5b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
78*5b4aa86bSJames Feist             {
79*5b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
80*5b4aa86bSJames Feist                 {
81*5b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
82*5b4aa86bSJames Feist                         intfPair.first != pidZoneConfigurationIface)
83*5b4aa86bSJames Feist                     {
84*5b4aa86bSJames Feist                         continue;
85*5b4aa86bSJames Feist                     }
86*5b4aa86bSJames Feist                     auto findName = intfPair.second.find("Name");
87*5b4aa86bSJames Feist                     if (findName == intfPair.second.end())
88*5b4aa86bSJames Feist                     {
89*5b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Field missing Name";
90*5b4aa86bSJames Feist                         asyncResp->res.result(
91*5b4aa86bSJames Feist                             boost::beast::http::status::internal_server_error);
92*5b4aa86bSJames Feist                         return;
93*5b4aa86bSJames Feist                     }
94*5b4aa86bSJames Feist                     const std::string* namePtr =
95*5b4aa86bSJames Feist                         mapbox::getPtr<const std::string>(findName->second);
96*5b4aa86bSJames Feist                     if (namePtr == nullptr)
97*5b4aa86bSJames Feist                     {
98*5b4aa86bSJames Feist                         BMCWEB_LOG_ERROR << "Pid Name Field illegal";
99*5b4aa86bSJames Feist                         return;
100*5b4aa86bSJames Feist                     }
101*5b4aa86bSJames Feist 
102*5b4aa86bSJames Feist                     std::string name = *namePtr;
103*5b4aa86bSJames Feist                     dbus::utility::escapePathForDbus(name);
104*5b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
105*5b4aa86bSJames Feist                     {
106*5b4aa86bSJames Feist                         std::string chassis;
107*5b4aa86bSJames Feist                         if (!dbus::utility::getNthStringFromPath(
108*5b4aa86bSJames Feist                                 pathPair.first.str, 5, chassis))
109*5b4aa86bSJames Feist                         {
110*5b4aa86bSJames Feist                             chassis = "#IllegalValue";
111*5b4aa86bSJames Feist                         }
112*5b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
113*5b4aa86bSJames Feist                         zone["Chassis"] = {
114*5b4aa86bSJames Feist                             {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
115*5b4aa86bSJames Feist                         zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
116*5b4aa86bSJames Feist                                             "OpenBmc/Fan/FanZones/" +
117*5b4aa86bSJames Feist                                             name;
118*5b4aa86bSJames Feist                         zone["@odata.type"] = "#OemManager.FanZone";
119*5b4aa86bSJames Feist                         zone["@odata.context"] =
120*5b4aa86bSJames Feist                             "/redfish/v1/$metadata#OemManager.FanZone";
121*5b4aa86bSJames Feist                     }
122*5b4aa86bSJames Feist 
123*5b4aa86bSJames Feist                     for (const auto& propertyPair : intfPair.second)
124*5b4aa86bSJames Feist                     {
125*5b4aa86bSJames Feist                         if (propertyPair.first == "Type" ||
126*5b4aa86bSJames Feist                             propertyPair.first == "Class" ||
127*5b4aa86bSJames Feist                             propertyPair.first == "Name")
128*5b4aa86bSJames Feist                         {
129*5b4aa86bSJames Feist                             continue;
130*5b4aa86bSJames Feist                         }
131*5b4aa86bSJames Feist 
132*5b4aa86bSJames Feist                         // zones
133*5b4aa86bSJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
134*5b4aa86bSJames Feist                         {
135*5b4aa86bSJames Feist                             const double* ptr = mapbox::getPtr<const double>(
136*5b4aa86bSJames Feist                                 propertyPair.second);
137*5b4aa86bSJames Feist                             if (ptr == nullptr)
138*5b4aa86bSJames Feist                             {
139*5b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Field Illegal "
140*5b4aa86bSJames Feist                                                  << propertyPair.first;
141*5b4aa86bSJames Feist                                 asyncResp->res.result(
142*5b4aa86bSJames Feist                                     boost::beast::http::status::
143*5b4aa86bSJames Feist                                         internal_server_error);
144*5b4aa86bSJames Feist                                 return;
145*5b4aa86bSJames Feist                             }
146*5b4aa86bSJames Feist                             zones[name][propertyPair.first] = *ptr;
147*5b4aa86bSJames Feist                         }
148*5b4aa86bSJames Feist 
149*5b4aa86bSJames Feist                         // pid and fans are off the same configuration
150*5b4aa86bSJames Feist                         if (intfPair.first == pidConfigurationIface)
151*5b4aa86bSJames Feist                         {
152*5b4aa86bSJames Feist                             const std::string* classPtr = nullptr;
153*5b4aa86bSJames Feist                             auto findClass = intfPair.second.find("Class");
154*5b4aa86bSJames Feist                             if (findClass != intfPair.second.end())
155*5b4aa86bSJames Feist                             {
156*5b4aa86bSJames Feist                                 classPtr = mapbox::getPtr<const std::string>(
157*5b4aa86bSJames Feist                                     findClass->second);
158*5b4aa86bSJames Feist                             }
159*5b4aa86bSJames Feist                             if (classPtr == nullptr)
160*5b4aa86bSJames Feist                             {
161*5b4aa86bSJames Feist                                 BMCWEB_LOG_ERROR << "Pid Class Field illegal";
162*5b4aa86bSJames Feist                                 asyncResp->res.result(
163*5b4aa86bSJames Feist                                     boost::beast::http::status::
164*5b4aa86bSJames Feist                                         internal_server_error);
165*5b4aa86bSJames Feist                                 return;
166*5b4aa86bSJames Feist                             }
167*5b4aa86bSJames Feist                             bool isFan = *classPtr == "fan";
168*5b4aa86bSJames Feist                             nlohmann::json& element =
169*5b4aa86bSJames Feist                                 isFan ? fans[name] : pids[name];
170*5b4aa86bSJames Feist                             if (isFan)
171*5b4aa86bSJames Feist                             {
172*5b4aa86bSJames Feist                                 element["@odata.id"] =
173*5b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
174*5b4aa86bSJames Feist                                     "OpenBmc/Fan/FanControllers/" +
175*5b4aa86bSJames Feist                                     std::string(name);
176*5b4aa86bSJames Feist                                 element["@odata.type"] =
177*5b4aa86bSJames Feist                                     "#OemManager.FanController";
178*5b4aa86bSJames Feist 
179*5b4aa86bSJames Feist                                 element["@odata.context"] =
180*5b4aa86bSJames Feist                                     "/redfish/v1/"
181*5b4aa86bSJames Feist                                     "$metadata#OemManager.FanController";
182*5b4aa86bSJames Feist                             }
183*5b4aa86bSJames Feist                             else
184*5b4aa86bSJames Feist                             {
185*5b4aa86bSJames Feist                                 element["@odata.id"] =
186*5b4aa86bSJames Feist                                     "/redfish/v1/Managers/bmc#/Oem/"
187*5b4aa86bSJames Feist                                     "OpenBmc/Fan/PidControllers/" +
188*5b4aa86bSJames Feist                                     std::string(name);
189*5b4aa86bSJames Feist                                 element["@odata.type"] =
190*5b4aa86bSJames Feist                                     "#OemManager.PidController";
191*5b4aa86bSJames Feist                                 element["@odata.context"] =
192*5b4aa86bSJames Feist                                     "/redfish/v1/$metadata"
193*5b4aa86bSJames Feist                                     "#OemManager.PidController";
194*5b4aa86bSJames Feist                             }
195*5b4aa86bSJames Feist 
196*5b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
197*5b4aa86bSJames Feist                             {
198*5b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
199*5b4aa86bSJames Feist                                     mapbox::getPtr<
200*5b4aa86bSJames Feist                                         const std::vector<std::string>>(
201*5b4aa86bSJames Feist                                         propertyPair.second);
202*5b4aa86bSJames Feist 
203*5b4aa86bSJames Feist                                 if (inputs == nullptr)
204*5b4aa86bSJames Feist                                 {
205*5b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR
206*5b4aa86bSJames Feist                                         << "Zones Pid Field Illegal";
207*5b4aa86bSJames Feist                                     asyncResp->res.result(
208*5b4aa86bSJames Feist                                         boost::beast::http::status::
209*5b4aa86bSJames Feist                                             internal_server_error);
210*5b4aa86bSJames Feist                                     return;
211*5b4aa86bSJames Feist                                 }
212*5b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
213*5b4aa86bSJames Feist                                 data = nlohmann::json::array();
214*5b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
215*5b4aa86bSJames Feist                                 {
216*5b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
217*5b4aa86bSJames Feist                                     data.push_back(
218*5b4aa86bSJames Feist                                         {{"@odata.id",
219*5b4aa86bSJames Feist                                           "/redfish/v1/Managers/bmc#/Oem/"
220*5b4aa86bSJames Feist                                           "OpenBmc/Fan/FanZones/" +
221*5b4aa86bSJames Feist                                               itemCopy}});
222*5b4aa86bSJames Feist                                 }
223*5b4aa86bSJames Feist                             }
224*5b4aa86bSJames Feist                             // todo(james): may never happen, but this
225*5b4aa86bSJames Feist                             // assumes configuration data referenced in the
226*5b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
227*5b4aa86bSJames Feist                             // could add another loop to cover all cases,
228*5b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
229*5b4aa86bSJames Feist                             // bit
230*5b4aa86bSJames Feist 
231*5b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
232*5b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
233*5b4aa86bSJames Feist                             {
234*5b4aa86bSJames Feist                                 auto& data = element[propertyPair.first];
235*5b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
236*5b4aa86bSJames Feist                                     mapbox::getPtr<
237*5b4aa86bSJames Feist                                         const std::vector<std::string>>(
238*5b4aa86bSJames Feist                                         propertyPair.second);
239*5b4aa86bSJames Feist 
240*5b4aa86bSJames Feist                                 if (inputs == nullptr)
241*5b4aa86bSJames Feist                                 {
242*5b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
243*5b4aa86bSJames Feist                                                      << propertyPair.first;
244*5b4aa86bSJames Feist                                     asyncResp->res.result(
245*5b4aa86bSJames Feist                                         boost::beast::http::status::
246*5b4aa86bSJames Feist                                             internal_server_error);
247*5b4aa86bSJames Feist                                     return;
248*5b4aa86bSJames Feist                                 }
249*5b4aa86bSJames Feist                                 data = *inputs;
250*5b4aa86bSJames Feist                             } // doubles
251*5b4aa86bSJames Feist                             else if (propertyPair.first ==
252*5b4aa86bSJames Feist                                          "FFGainCoefficient" ||
253*5b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
254*5b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
255*5b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
256*5b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
257*5b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
258*5b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
259*5b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
260*5b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
261*5b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
262*5b4aa86bSJames Feist                             {
263*5b4aa86bSJames Feist                                 const double* ptr =
264*5b4aa86bSJames Feist                                     mapbox::getPtr<const double>(
265*5b4aa86bSJames Feist                                         propertyPair.second);
266*5b4aa86bSJames Feist                                 if (ptr == nullptr)
267*5b4aa86bSJames Feist                                 {
268*5b4aa86bSJames Feist                                     BMCWEB_LOG_ERROR << "Field Illegal "
269*5b4aa86bSJames Feist                                                      << propertyPair.first;
270*5b4aa86bSJames Feist                                     asyncResp->res.result(
271*5b4aa86bSJames Feist                                         boost::beast::http::status::
272*5b4aa86bSJames Feist                                             internal_server_error);
273*5b4aa86bSJames Feist                                     return;
274*5b4aa86bSJames Feist                                 }
275*5b4aa86bSJames Feist                                 element[propertyPair.first] = *ptr;
276*5b4aa86bSJames Feist                             }
277*5b4aa86bSJames Feist                         }
278*5b4aa86bSJames Feist                     }
279*5b4aa86bSJames Feist                 }
280*5b4aa86bSJames Feist             }
281*5b4aa86bSJames Feist         },
282*5b4aa86bSJames Feist         connection, path, objectManagerIface, "GetManagedObjects");
283*5b4aa86bSJames Feist }
284ca537928SJennifer Lee 
2851abe55efSEd Tanous class Manager : public Node
2861abe55efSEd Tanous {
2879c310685SBorawski.Lukasz   public:
288*5b4aa86bSJames Feist     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
2891abe55efSEd Tanous     {
290*5b4aa86bSJames Feist         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc";
2919c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
2929c310685SBorawski.Lukasz         Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
293*5b4aa86bSJames Feist         Node::json["Id"] = "bmc";
2949c310685SBorawski.Lukasz         Node::json["Name"] = "OpenBmc Manager";
2959c310685SBorawski.Lukasz         Node::json["Description"] = "Baseboard Management Controller";
2969c310685SBorawski.Lukasz         Node::json["PowerState"] = "On";
297ca537928SJennifer Lee         Node::json["ManagerType"] = "BMC";
2989c310685SBorawski.Lukasz         Node::json["UUID"] =
29955c7b7a2SEd Tanous             app.template getMiddleware<crow::persistent_data::Middleware>()
30055c7b7a2SEd Tanous                 .systemUuid;
3019c310685SBorawski.Lukasz         Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
302ca537928SJennifer Lee         Node::json["EthernetInterfaces"] = {
303*5b4aa86bSJames Feist             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
3043ebd75f7SEd Tanous 
305a434f2bdSEd Tanous         entityPrivileges = {
306a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
307e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
308e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
309e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
310e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
311e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
312*5b4aa86bSJames Feist 
313*5b4aa86bSJames Feist         // default oem data
314*5b4aa86bSJames Feist         nlohmann::json& oem = Node::json["Oem"];
315*5b4aa86bSJames Feist         nlohmann::json& oemOpenbmc = oem["OpenBmc"];
316*5b4aa86bSJames Feist         oem["@odata.type"] = "#OemManager.Oem";
317*5b4aa86bSJames Feist         oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
318*5b4aa86bSJames Feist         oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
319*5b4aa86bSJames Feist         oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
320*5b4aa86bSJames Feist         oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
321*5b4aa86bSJames Feist         oemOpenbmc["@odata.context"] =
322*5b4aa86bSJames Feist             "/redfish/v1/$metadata#OemManager.OpenBmc";
3239c310685SBorawski.Lukasz     }
3249c310685SBorawski.Lukasz 
3259c310685SBorawski.Lukasz   private:
326*5b4aa86bSJames Feist     void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
327*5b4aa86bSJames Feist     {
328*5b4aa86bSJames Feist         crow::connections::systemBus->async_method_call(
329*5b4aa86bSJames Feist             [asyncResp](const boost::system::error_code ec,
330*5b4aa86bSJames Feist                         const crow::openbmc_mapper::GetSubTreeType& subtree) {
331*5b4aa86bSJames Feist                 if (ec)
332*5b4aa86bSJames Feist                 {
333*5b4aa86bSJames Feist                     BMCWEB_LOG_ERROR << ec;
334*5b4aa86bSJames Feist                     asyncResp->res.result(
335*5b4aa86bSJames Feist                         boost::beast::http::status::internal_server_error);
336*5b4aa86bSJames Feist                     return;
337*5b4aa86bSJames Feist                 }
338*5b4aa86bSJames Feist 
339*5b4aa86bSJames Feist                 // create map of <connection, path to objMgr>>
340*5b4aa86bSJames Feist                 boost::container::flat_map<std::string, std::string>
341*5b4aa86bSJames Feist                     objectMgrPaths;
342*5b4aa86bSJames Feist                 for (const auto& pathGroup : subtree)
343*5b4aa86bSJames Feist                 {
344*5b4aa86bSJames Feist                     for (const auto& connectionGroup : pathGroup.second)
345*5b4aa86bSJames Feist                     {
346*5b4aa86bSJames Feist                         for (const std::string& interface :
347*5b4aa86bSJames Feist                              connectionGroup.second)
348*5b4aa86bSJames Feist                         {
349*5b4aa86bSJames Feist                             if (interface == objectManagerIface)
350*5b4aa86bSJames Feist                             {
351*5b4aa86bSJames Feist                                 objectMgrPaths[connectionGroup.first] =
352*5b4aa86bSJames Feist                                     pathGroup.first;
353*5b4aa86bSJames Feist                             }
354*5b4aa86bSJames Feist                             // this list is alphabetical, so we
355*5b4aa86bSJames Feist                             // should have found the objMgr by now
356*5b4aa86bSJames Feist                             if (interface == pidConfigurationIface ||
357*5b4aa86bSJames Feist                                 interface == pidZoneConfigurationIface)
358*5b4aa86bSJames Feist                             {
359*5b4aa86bSJames Feist                                 auto findObjMgr =
360*5b4aa86bSJames Feist                                     objectMgrPaths.find(connectionGroup.first);
361*5b4aa86bSJames Feist                                 if (findObjMgr == objectMgrPaths.end())
362*5b4aa86bSJames Feist                                 {
363*5b4aa86bSJames Feist                                     BMCWEB_LOG_DEBUG << connectionGroup.first
364*5b4aa86bSJames Feist                                                      << "Has no Object Manager";
365*5b4aa86bSJames Feist                                     continue;
366*5b4aa86bSJames Feist                                 }
367*5b4aa86bSJames Feist                                 asyncPopulatePid(findObjMgr->first,
368*5b4aa86bSJames Feist                                                  findObjMgr->second, asyncResp);
369*5b4aa86bSJames Feist                                 break;
370*5b4aa86bSJames Feist                             }
371*5b4aa86bSJames Feist                         }
372*5b4aa86bSJames Feist                     }
373*5b4aa86bSJames Feist                 }
374*5b4aa86bSJames Feist             },
375*5b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper",
376*5b4aa86bSJames Feist             "/xyz/openbmc_project/object_mapper",
377*5b4aa86bSJames Feist             "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
378*5b4aa86bSJames Feist             std::array<const char*, 3>{pidConfigurationIface,
379*5b4aa86bSJames Feist                                        pidZoneConfigurationIface,
380*5b4aa86bSJames Feist                                        objectManagerIface});
381*5b4aa86bSJames Feist     }
382*5b4aa86bSJames Feist 
38355c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
3841abe55efSEd Tanous                const std::vector<std::string>& params) override
3851abe55efSEd Tanous     {
386ca537928SJennifer Lee         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
387ca537928SJennifer Lee         asyncResp->res.jsonValue = Node::json;
388ca537928SJennifer Lee 
3899c310685SBorawski.Lukasz         Node::json["DateTime"] = getDateTime();
39055c7b7a2SEd Tanous         res.jsonValue = Node::json;
391*5b4aa86bSJames Feist 
392ca537928SJennifer Lee         crow::connections::systemBus->async_method_call(
393ca537928SJennifer Lee             [asyncResp](const boost::system::error_code ec,
394*5b4aa86bSJames Feist                         const dbus::utility::ManagedObjectType& resp) {
395ca537928SJennifer Lee                 if (ec)
396ca537928SJennifer Lee                 {
397ca537928SJennifer Lee                     BMCWEB_LOG_ERROR << "Error while getting Software Version";
398ca537928SJennifer Lee                     asyncResp->res.result(
399ca537928SJennifer Lee                         boost::beast::http::status::internal_server_error);
400ca537928SJennifer Lee                     return;
401ca537928SJennifer Lee                 }
402ca537928SJennifer Lee 
403ca537928SJennifer Lee                 for (auto& objpath : resp)
404ca537928SJennifer Lee                 {
405ca537928SJennifer Lee                     for (auto& interface : objpath.second)
406ca537928SJennifer Lee                     {
407ca537928SJennifer Lee                         // If interface is xyz.openbmc_project.Software.Version,
408ca537928SJennifer Lee                         // this is what we're looking for.
409ca537928SJennifer Lee                         if (interface.first ==
410ca537928SJennifer Lee                             "xyz.openbmc_project.Software.Version")
411ca537928SJennifer Lee                         {
412ca537928SJennifer Lee                             // Cut out everyting until last "/", ...
413ca537928SJennifer Lee                             const std::string& iface_id = objpath.first;
414ca537928SJennifer Lee                             for (auto& property : interface.second)
415ca537928SJennifer Lee                             {
416ca537928SJennifer Lee                                 if (property.first == "Version")
417ca537928SJennifer Lee                                 {
418ca537928SJennifer Lee                                     const std::string* value =
419ca537928SJennifer Lee                                         mapbox::getPtr<const std::string>(
420ca537928SJennifer Lee                                             property.second);
421ca537928SJennifer Lee                                     if (value == nullptr)
422ca537928SJennifer Lee                                     {
423ca537928SJennifer Lee                                         continue;
424ca537928SJennifer Lee                                     }
425ca537928SJennifer Lee                                     asyncResp->res
426ca537928SJennifer Lee                                         .jsonValue["FirmwareVersion"] = *value;
427ca537928SJennifer Lee                                 }
428ca537928SJennifer Lee                             }
429ca537928SJennifer Lee                         }
430ca537928SJennifer Lee                     }
431ca537928SJennifer Lee                 }
432ca537928SJennifer Lee             },
433ca537928SJennifer Lee             "xyz.openbmc_project.Software.BMC.Updater",
434ca537928SJennifer Lee             "/xyz/openbmc_project/software",
435ca537928SJennifer Lee             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
436*5b4aa86bSJames Feist         getPidValues(asyncResp);
437*5b4aa86bSJames Feist     }
438*5b4aa86bSJames Feist 
439*5b4aa86bSJames Feist     void doPatch(crow::Response& res, const crow::Request& req,
440*5b4aa86bSJames Feist                  const std::vector<std::string>& params) override
441*5b4aa86bSJames Feist     {
4429c310685SBorawski.Lukasz     }
4439c310685SBorawski.Lukasz 
4441abe55efSEd Tanous     std::string getDateTime() const
4451abe55efSEd Tanous     {
4469c310685SBorawski.Lukasz         std::array<char, 128> dateTime;
4479c310685SBorawski.Lukasz         std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
4489c310685SBorawski.Lukasz         std::time_t time = std::time(nullptr);
4499c310685SBorawski.Lukasz 
4509c310685SBorawski.Lukasz         if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
4511abe55efSEd Tanous                           std::localtime(&time)))
4521abe55efSEd Tanous         {
4539c310685SBorawski.Lukasz             // insert the colon required by the ISO 8601 standard
4549c310685SBorawski.Lukasz             redfishDateTime = std::string(dateTime.data());
4559c310685SBorawski.Lukasz             redfishDateTime.insert(redfishDateTime.end() - 2, ':');
4569c310685SBorawski.Lukasz         }
4579c310685SBorawski.Lukasz 
4589c310685SBorawski.Lukasz         return redfishDateTime;
4599c310685SBorawski.Lukasz     }
4609c310685SBorawski.Lukasz };
4619c310685SBorawski.Lukasz 
4621abe55efSEd Tanous class ManagerCollection : public Node
4631abe55efSEd Tanous {
4649c310685SBorawski.Lukasz   public:
4651abe55efSEd Tanous     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
4661abe55efSEd Tanous     {
4679c310685SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/Managers";
4689c310685SBorawski.Lukasz         Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
4699c310685SBorawski.Lukasz         Node::json["@odata.context"] =
4709c310685SBorawski.Lukasz             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
4719c310685SBorawski.Lukasz         Node::json["Name"] = "Manager Collection";
4729c310685SBorawski.Lukasz         Node::json["Members@odata.count"] = 1;
473*5b4aa86bSJames Feist         Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}};
4743ebd75f7SEd Tanous 
475a434f2bdSEd Tanous         entityPrivileges = {
476a434f2bdSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
477e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
478e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
479e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
480e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
481e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
4829c310685SBorawski.Lukasz     }
4839c310685SBorawski.Lukasz 
4849c310685SBorawski.Lukasz   private:
48555c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
4861abe55efSEd Tanous                const std::vector<std::string>& params) override
4871abe55efSEd Tanous     {
4881abe55efSEd Tanous         // Collections don't include the static data added by SubRoute because
4891abe55efSEd Tanous         // it has a duplicate entry for members
49055c7b7a2SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
49155c7b7a2SEd Tanous         res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
49255c7b7a2SEd Tanous         res.jsonValue["@odata.context"] =
49355c7b7a2SEd Tanous             "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
49455c7b7a2SEd Tanous         res.jsonValue["Name"] = "Manager Collection";
49555c7b7a2SEd Tanous         res.jsonValue["Members@odata.count"] = 1;
49655c7b7a2SEd Tanous         res.jsonValue["Members"] = {
497*5b4aa86bSJames Feist             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
4989c310685SBorawski.Lukasz         res.end();
4999c310685SBorawski.Lukasz     }
5009c310685SBorawski.Lukasz };
5019c310685SBorawski.Lukasz } // namespace redfish
502