xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 1abe55ef9844afcddcab9d862ae06118f3a2390c)
1e37f8451SRapkiewicz, Pawel /*
2e37f8451SRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation
3e37f8451SRapkiewicz, Pawel //
4e37f8451SRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License");
5e37f8451SRapkiewicz, Pawel // you may not use this file except in compliance with the License.
6e37f8451SRapkiewicz, Pawel // You may obtain a copy of the License at
7e37f8451SRapkiewicz, Pawel //
8e37f8451SRapkiewicz, Pawel //      http://www.apache.org/licenses/LICENSE-2.0
9e37f8451SRapkiewicz, Pawel //
10e37f8451SRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software
11e37f8451SRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS,
12e37f8451SRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e37f8451SRapkiewicz, Pawel // See the License for the specific language governing permissions and
14e37f8451SRapkiewicz, Pawel // limitations under the License.
15e37f8451SRapkiewicz, Pawel */
16e37f8451SRapkiewicz, Pawel #pragma once
17e37f8451SRapkiewicz, Pawel 
18e37f8451SRapkiewicz, Pawel #include "node.hpp"
19*1abe55efSEd Tanous 
20e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp>
21e37f8451SRapkiewicz, Pawel 
22*1abe55efSEd Tanous namespace redfish
23*1abe55efSEd Tanous {
24e37f8451SRapkiewicz, Pawel 
25e37f8451SRapkiewicz, Pawel /**
26e37f8451SRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
27e37f8451SRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
28e37f8451SRapkiewicz, Pawel  */
2955c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get
30aa2e59c1SEd Tanous // values, it should be as simple as possible
31aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type
32c5b2abe0SLewanczyk, Dawid using VariantType = sdbusplus::message::variant<bool, std::string>;
33aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair<
34aa2e59c1SEd Tanous     sdbusplus::message::object_path,
35aa2e59c1SEd Tanous     std::vector<std::pair<std::string,
36aa2e59c1SEd Tanous                           std::vector<std::pair<std::string, VariantType>>>>>>;
37e37f8451SRapkiewicz, Pawel 
38aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>;
39e37f8451SRapkiewicz, Pawel 
40e37f8451SRapkiewicz, Pawel /**
41e37f8451SRapkiewicz, Pawel  * OnDemandChassisProvider
42274fad5aSGunnar Mills  * Chassis provider class that retrieves data directly from dbus, before setting
43e37f8451SRapkiewicz, Pawel  * it into JSON output. This does not cache any data.
44e37f8451SRapkiewicz, Pawel  *
45e37f8451SRapkiewicz, Pawel  * Class can be a good example on how to scale different data providing
46e37f8451SRapkiewicz, Pawel  * solutions to produce single schema output.
47e37f8451SRapkiewicz, Pawel  *
48e37f8451SRapkiewicz, Pawel  * TODO(Pawel)
49e37f8451SRapkiewicz, Pawel  * This perhaps shall be different file, which has to be chosen on compile time
50e37f8451SRapkiewicz, Pawel  * depending on OEM needs
51e37f8451SRapkiewicz, Pawel  */
52*1abe55efSEd Tanous class OnDemandChassisProvider
53*1abe55efSEd Tanous {
54e37f8451SRapkiewicz, Pawel   public:
55e37f8451SRapkiewicz, Pawel     /**
56e37f8451SRapkiewicz, Pawel      * Function that retrieves all Chassis available through EntityManager.
57*1abe55efSEd Tanous      * @param callback a function that shall be called to convert Dbus output
58*1abe55efSEd Tanous      * into JSON.
59e37f8451SRapkiewicz, Pawel      */
60e37f8451SRapkiewicz, Pawel     template <typename CallbackFunc>
61*1abe55efSEd Tanous     void getChassisList(CallbackFunc &&callback)
62*1abe55efSEd Tanous     {
63daf36e2eSEd Tanous         const std::array<const char *, 4> interfaces = {
64daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Item.Board",
65daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Item.Chassis",
66daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Item.PowerSupply",
67daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Item.System",
68daf36e2eSEd Tanous         };
6955c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
70e37f8451SRapkiewicz, Pawel             [callback{std::move(callback)}](
71e37f8451SRapkiewicz, Pawel                 const boost::system::error_code error_code,
72daf36e2eSEd Tanous                 const std::vector<std::string> &resp) {
73*1abe55efSEd Tanous                 // Callback requires vector<string> to retrieve all available
74*1abe55efSEd Tanous                 // chassis list.
7555c7b7a2SEd Tanous                 std::vector<std::string> chassisList;
76*1abe55efSEd Tanous                 if (error_code)
77*1abe55efSEd Tanous                 {
78*1abe55efSEd Tanous                     // Something wrong on DBus, the error_code is not important
79*1abe55efSEd Tanous                     // at this moment, just return success=false, and empty
80*1abe55efSEd Tanous                     // output. Since size of vector may vary depending on
81*1abe55efSEd Tanous                     // information from Entity Manager, and empty output could
82*1abe55efSEd Tanous                     // not be treated same way as error.
8355c7b7a2SEd Tanous                     callback(false, chassisList);
84e37f8451SRapkiewicz, Pawel                     return;
85e37f8451SRapkiewicz, Pawel                 }
86e37f8451SRapkiewicz, Pawel                 // Iterate over all retrieved ObjectPaths.
87*1abe55efSEd Tanous                 for (const std::string &objpath : resp)
88*1abe55efSEd Tanous                 {
8955c7b7a2SEd Tanous                     std::size_t lastPos = objpath.rfind("/");
90*1abe55efSEd Tanous                     if (lastPos != std::string::npos)
91*1abe55efSEd Tanous                     {
92e37f8451SRapkiewicz, Pawel                         // and put it into output vector.
9355c7b7a2SEd Tanous                         chassisList.emplace_back(objpath.substr(lastPos + 1));
94e37f8451SRapkiewicz, Pawel                     }
95e37f8451SRapkiewicz, Pawel                 }
96a434f2bdSEd Tanous                 // Finally make a callback with useful data
9755c7b7a2SEd Tanous                 callback(true, chassisList);
98e37f8451SRapkiewicz, Pawel             },
99daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper",
100daf36e2eSEd Tanous             "/xyz/openbmc_project/object_mapper",
101daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
102daf36e2eSEd Tanous             "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
103e37f8451SRapkiewicz, Pawel     };
104e37f8451SRapkiewicz, Pawel };
105e37f8451SRapkiewicz, Pawel 
106e37f8451SRapkiewicz, Pawel /**
107e37f8451SRapkiewicz, Pawel  * ChassisCollection derived class for delivering Chassis Collection Schema
108e37f8451SRapkiewicz, Pawel  */
109*1abe55efSEd Tanous class ChassisCollection : public Node
110*1abe55efSEd Tanous {
111e37f8451SRapkiewicz, Pawel   public:
112*1abe55efSEd Tanous     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
113*1abe55efSEd Tanous     {
114e37f8451SRapkiewicz, Pawel         Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
115e37f8451SRapkiewicz, Pawel         Node::json["@odata.id"] = "/redfish/v1/Chassis";
116e37f8451SRapkiewicz, Pawel         Node::json["@odata.context"] =
117e37f8451SRapkiewicz, Pawel             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
118e37f8451SRapkiewicz, Pawel         Node::json["Name"] = "Chassis Collection";
119e37f8451SRapkiewicz, Pawel 
120e0d918bcSEd Tanous         entityPrivileges = {
121e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
122e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
123e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
124e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
125e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
126e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
127e37f8451SRapkiewicz, Pawel     }
128e37f8451SRapkiewicz, Pawel 
129e37f8451SRapkiewicz, Pawel   private:
130e37f8451SRapkiewicz, Pawel     /**
131e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
132e37f8451SRapkiewicz, Pawel      */
13355c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
134*1abe55efSEd Tanous                const std::vector<std::string> &params) override
135*1abe55efSEd Tanous     {
13655c7b7a2SEd Tanous         // get chassis list, and call the below callback for JSON preparation
13755c7b7a2SEd Tanous         chassisProvider.getChassisList(
138e37f8451SRapkiewicz, Pawel             [&](const bool &success, const std::vector<std::string> &output) {
139*1abe55efSEd Tanous                 if (success)
140*1abe55efSEd Tanous                 {
141e37f8451SRapkiewicz, Pawel                     // ... prepare json array with appropriate @odata.id links
14255c7b7a2SEd Tanous                     nlohmann::json chassisArray = nlohmann::json::array();
143*1abe55efSEd Tanous                     for (const std::string &chassisItem : output)
144*1abe55efSEd Tanous                     {
14555c7b7a2SEd Tanous                         chassisArray.push_back(
146*1abe55efSEd Tanous                             {{"@odata.id",
147*1abe55efSEd Tanous                               "/redfish/v1/Chassis/" + chassisItem}});
148e37f8451SRapkiewicz, Pawel                     }
149e37f8451SRapkiewicz, Pawel                     // Then attach members, count size and return,
15055c7b7a2SEd Tanous                     Node::json["Members"] = chassisArray;
15155c7b7a2SEd Tanous                     Node::json["Members@odata.count"] = chassisArray.size();
15255c7b7a2SEd Tanous                     res.jsonValue = Node::json;
153*1abe55efSEd Tanous                 }
154*1abe55efSEd Tanous                 else
155*1abe55efSEd Tanous                 {
156e37f8451SRapkiewicz, Pawel                     // ... otherwise, return INTERNALL ERROR
157*1abe55efSEd Tanous                     res.result(
158*1abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
159e37f8451SRapkiewicz, Pawel                 }
160e37f8451SRapkiewicz, Pawel                 res.end();
161e37f8451SRapkiewicz, Pawel             });
162e37f8451SRapkiewicz, Pawel     }
163e37f8451SRapkiewicz, Pawel 
164e37f8451SRapkiewicz, Pawel     // Chassis Provider object
165e37f8451SRapkiewicz, Pawel     // TODO(Pawel) consider move it to singleton
16655c7b7a2SEd Tanous     OnDemandChassisProvider chassisProvider;
167e37f8451SRapkiewicz, Pawel };
168e37f8451SRapkiewicz, Pawel 
169e37f8451SRapkiewicz, Pawel /**
170e37f8451SRapkiewicz, Pawel  * Chassis override class for delivering Chassis Schema
171e37f8451SRapkiewicz, Pawel  */
172*1abe55efSEd Tanous class Chassis : public Node
173*1abe55efSEd Tanous {
174e37f8451SRapkiewicz, Pawel   public:
175*1abe55efSEd Tanous     Chassis(CrowApp &app) :
176*1abe55efSEd Tanous         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
177*1abe55efSEd Tanous     {
178e37f8451SRapkiewicz, Pawel         Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
179e37f8451SRapkiewicz, Pawel         Node::json["@odata.id"] = "/redfish/v1/Chassis";
180e37f8451SRapkiewicz, Pawel         Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
181e37f8451SRapkiewicz, Pawel         Node::json["Name"] = "Chassis Collection";
1826c233015SEd Tanous         Node::json["ChassisType"] = "RackMount";
183e37f8451SRapkiewicz, Pawel 
184e0d918bcSEd Tanous         entityPrivileges = {
185e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
186e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
187e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
188e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
189e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
190e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
191e37f8451SRapkiewicz, Pawel     }
192e37f8451SRapkiewicz, Pawel 
193e37f8451SRapkiewicz, Pawel   private:
194e37f8451SRapkiewicz, Pawel     /**
195e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
196e37f8451SRapkiewicz, Pawel      */
19755c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
198*1abe55efSEd Tanous                const std::vector<std::string> &params) override
199*1abe55efSEd Tanous     {
200e37f8451SRapkiewicz, Pawel         // Check if there is required param, truly entering this shall be
201e37f8451SRapkiewicz, Pawel         // impossible.
202*1abe55efSEd Tanous         if (params.size() != 1)
203*1abe55efSEd Tanous         {
204e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
205e37f8451SRapkiewicz, Pawel             res.end();
206e37f8451SRapkiewicz, Pawel             return;
207e37f8451SRapkiewicz, Pawel         }
208e37f8451SRapkiewicz, Pawel 
20955c7b7a2SEd Tanous         res.jsonValue = Node::json;
21055c7b7a2SEd Tanous         const std::string &chassisId = params[0];
21155c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
21255c7b7a2SEd Tanous             [&res, chassisId(std::string(chassisId))](
213daf36e2eSEd Tanous                 const boost::system::error_code error_code,
214daf36e2eSEd Tanous                 const std::vector<std::pair<
215*1abe55efSEd Tanous                     std::string, std::vector<std::pair<
216*1abe55efSEd Tanous                                      std::string, std::vector<std::string>>>>>
217daf36e2eSEd Tanous                     &subtree) {
218*1abe55efSEd Tanous                 if (error_code)
219*1abe55efSEd Tanous                 {
22055c7b7a2SEd Tanous                     res.jsonValue = {};
221*1abe55efSEd Tanous                     res.result(
222*1abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
223e37f8451SRapkiewicz, Pawel                     res.end();
224daf36e2eSEd Tanous                     return;
225daf36e2eSEd Tanous                 }
226daf36e2eSEd Tanous                 // Iterate over all retrieved ObjectPaths.
227*1abe55efSEd Tanous                 for (const std::pair<
228*1abe55efSEd Tanous                          std::string,
229*1abe55efSEd Tanous                          std::vector<
230*1abe55efSEd Tanous                              std::pair<std::string, std::vector<std::string>>>>
231*1abe55efSEd Tanous                          &object : subtree)
232*1abe55efSEd Tanous                 {
233daf36e2eSEd Tanous                     const std::string &path = object.first;
234*1abe55efSEd Tanous                     const std::vector<
235*1abe55efSEd Tanous                         std::pair<std::string, std::vector<std::string>>>
236daf36e2eSEd Tanous                         &connectionNames = object.second;
237e0d918bcSEd Tanous 
238*1abe55efSEd Tanous                     if (!boost::ends_with(path, chassisId))
239*1abe55efSEd Tanous                     {
240daf36e2eSEd Tanous                         continue;
241daf36e2eSEd Tanous                     }
242*1abe55efSEd Tanous                     if (connectionNames.size() < 1)
243*1abe55efSEd Tanous                     {
244*1abe55efSEd Tanous                         BMCWEB_LOG_ERROR << "Only got "
245*1abe55efSEd Tanous                                          << connectionNames.size()
24655c7b7a2SEd Tanous                                          << " Connection names";
247e0d918bcSEd Tanous                         continue;
248daf36e2eSEd Tanous                     }
249e0d918bcSEd Tanous 
250daf36e2eSEd Tanous                     const std::string connectionName = connectionNames[0].first;
25155c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
25255c7b7a2SEd Tanous                         [&res, chassisId(std::string(chassisId))](
253daf36e2eSEd Tanous                             const boost::system::error_code error_code,
254*1abe55efSEd Tanous                             const std::vector<std::pair<
255*1abe55efSEd Tanous                                 std::string, VariantType>> &propertiesList) {
256*1abe55efSEd Tanous                             for (const std::pair<std::string, VariantType>
257*1abe55efSEd Tanous                                      &property : propertiesList)
258*1abe55efSEd Tanous                             {
259daf36e2eSEd Tanous                                 const std::string *value =
260*1abe55efSEd Tanous                                     mapbox::getPtr<const std::string>(
261*1abe55efSEd Tanous                                         property.second);
262*1abe55efSEd Tanous                                 if (value != nullptr)
263*1abe55efSEd Tanous                                 {
26455c7b7a2SEd Tanous                                     res.jsonValue[property.first] = *value;
265daf36e2eSEd Tanous                                 }
266daf36e2eSEd Tanous                             }
26755c7b7a2SEd Tanous                             res.jsonValue["Name"] = chassisId;
26855c7b7a2SEd Tanous                             res.jsonValue["Id"] = chassisId;
26955c7b7a2SEd Tanous                             res.jsonValue["Thermal"] = {
270*1abe55efSEd Tanous                                 {"@odata.id", "/redfish/v1/Chassis/" +
271*1abe55efSEd Tanous                                                   chassisId + "/Thermal"}};
272daf36e2eSEd Tanous                             res.end();
273daf36e2eSEd Tanous                         },
274daf36e2eSEd Tanous                         connectionName, path, "org.freedesktop.DBus.Properties",
275*1abe55efSEd Tanous                         "GetAll",
276*1abe55efSEd Tanous                         "xyz.openbmc_project.Inventory.Decorator.Asset");
27755c7b7a2SEd Tanous                     // Found the Connection we were looking for, return
278daf36e2eSEd Tanous                     return;
279daf36e2eSEd Tanous                 }
280e0d918bcSEd Tanous 
281daf36e2eSEd Tanous                 // Couldn't find an object with that name.  return an error
282e0d918bcSEd Tanous                 res.result(boost::beast::http::status::not_found);
283e0d918bcSEd Tanous 
284daf36e2eSEd Tanous                 res.end();
285daf36e2eSEd Tanous             },
286daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper",
287daf36e2eSEd Tanous             "/xyz/openbmc_project/object_mapper",
288daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
289daf36e2eSEd Tanous             "/xyz/openbmc_project/inventory", int32_t(0),
290daf36e2eSEd Tanous             std::array<const char *, 1>{
291daf36e2eSEd Tanous                 "xyz.openbmc_project.Inventory.Decorator.Asset"});
292e37f8451SRapkiewicz, Pawel     }
293e37f8451SRapkiewicz, Pawel 
294e37f8451SRapkiewicz, Pawel     // Chassis Provider object
295e37f8451SRapkiewicz, Pawel     // TODO(Pawel) consider move it to singleton
29655c7b7a2SEd Tanous     OnDemandChassisProvider chassisProvider;
297e0d918bcSEd Tanous }; // namespace redfish
298e37f8451SRapkiewicz, Pawel 
299e37f8451SRapkiewicz, Pawel } // namespace redfish
300