xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision a434f2bde1f80e1a0ddcda0961a7ff102de152d6)
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"
19e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp>
20e37f8451SRapkiewicz, Pawel 
21e37f8451SRapkiewicz, Pawel namespace redfish {
22e37f8451SRapkiewicz, Pawel 
23e37f8451SRapkiewicz, Pawel /**
24e37f8451SRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
25e37f8451SRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
26e37f8451SRapkiewicz, Pawel  */
2755c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get
28aa2e59c1SEd Tanous // values, it should be as simple as possible
29aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type
30c5b2abe0SLewanczyk, Dawid using VariantType = sdbusplus::message::variant<bool, std::string>;
31aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair<
32aa2e59c1SEd Tanous     sdbusplus::message::object_path,
33aa2e59c1SEd Tanous     std::vector<std::pair<std::string,
34aa2e59c1SEd Tanous                           std::vector<std::pair<std::string, VariantType>>>>>>;
35e37f8451SRapkiewicz, Pawel 
36aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>;
37e37f8451SRapkiewicz, Pawel 
38e37f8451SRapkiewicz, Pawel /**
39e37f8451SRapkiewicz, Pawel  * OnDemandChassisProvider
40274fad5aSGunnar Mills  * Chassis provider class that retrieves data directly from dbus, before setting
41e37f8451SRapkiewicz, Pawel  * it into JSON output. This does not cache any data.
42e37f8451SRapkiewicz, Pawel  *
43e37f8451SRapkiewicz, Pawel  * Class can be a good example on how to scale different data providing
44e37f8451SRapkiewicz, Pawel  * solutions to produce single schema output.
45e37f8451SRapkiewicz, Pawel  *
46e37f8451SRapkiewicz, Pawel  * TODO(Pawel)
47e37f8451SRapkiewicz, Pawel  * This perhaps shall be different file, which has to be chosen on compile time
48e37f8451SRapkiewicz, Pawel  * depending on OEM needs
49e37f8451SRapkiewicz, Pawel  */
50e37f8451SRapkiewicz, Pawel class OnDemandChassisProvider {
51e37f8451SRapkiewicz, Pawel  public:
52e37f8451SRapkiewicz, Pawel   /**
53e37f8451SRapkiewicz, Pawel    * Function that retrieves all Chassis available through EntityManager.
54e37f8451SRapkiewicz, Pawel    * @param callback a function that shall be called to convert Dbus output into
55e37f8451SRapkiewicz, Pawel    * JSON.
56e37f8451SRapkiewicz, Pawel    */
57e37f8451SRapkiewicz, Pawel   template <typename CallbackFunc>
5855c7b7a2SEd Tanous   void getChassisList(CallbackFunc &&callback) {
59daf36e2eSEd Tanous     const std::array<const char *, 4> interfaces = {
60daf36e2eSEd Tanous         "xyz.openbmc_project.Inventory.Item.Board",
61daf36e2eSEd Tanous         "xyz.openbmc_project.Inventory.Item.Chassis",
62daf36e2eSEd Tanous         "xyz.openbmc_project.Inventory.Item.PowerSupply",
63daf36e2eSEd Tanous         "xyz.openbmc_project.Inventory.Item.System",
64daf36e2eSEd Tanous     };
6555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
66e37f8451SRapkiewicz, Pawel         [callback{std::move(callback)}](
67e37f8451SRapkiewicz, Pawel             const boost::system::error_code error_code,
68daf36e2eSEd Tanous             const std::vector<std::string> &resp) {
69e37f8451SRapkiewicz, Pawel           // Callback requires vector<string> to retrieve all available chassis
70e37f8451SRapkiewicz, Pawel           // list.
7155c7b7a2SEd Tanous           std::vector<std::string> chassisList;
72e37f8451SRapkiewicz, Pawel           if (error_code) {
73e37f8451SRapkiewicz, Pawel             // Something wrong on DBus, the error_code is not important at this
74e37f8451SRapkiewicz, Pawel             // moment, just return success=false, and empty output. Since size
75e37f8451SRapkiewicz, Pawel             // of vector may vary depending on information from Entity Manager,
76e37f8451SRapkiewicz, Pawel             // and empty output could not be treated same way as error.
7755c7b7a2SEd Tanous             callback(false, chassisList);
78e37f8451SRapkiewicz, Pawel             return;
79e37f8451SRapkiewicz, Pawel           }
80e37f8451SRapkiewicz, Pawel           // Iterate over all retrieved ObjectPaths.
81daf36e2eSEd Tanous           for (const std::string &objpath : resp) {
8255c7b7a2SEd Tanous             std::size_t lastPos = objpath.rfind("/");
8355c7b7a2SEd Tanous             if (lastPos != std::string::npos) {
84e37f8451SRapkiewicz, Pawel               // and put it into output vector.
8555c7b7a2SEd Tanous               chassisList.emplace_back(objpath.substr(lastPos + 1));
86e37f8451SRapkiewicz, Pawel             }
87e37f8451SRapkiewicz, Pawel           }
88*a434f2bdSEd Tanous           // Finally make a callback with useful data
8955c7b7a2SEd Tanous           callback(true, chassisList);
90e37f8451SRapkiewicz, Pawel         },
91daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper",
92daf36e2eSEd Tanous         "/xyz/openbmc_project/object_mapper",
93daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
94daf36e2eSEd Tanous         "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
95e37f8451SRapkiewicz, Pawel   };
96e37f8451SRapkiewicz, Pawel };
97e37f8451SRapkiewicz, Pawel 
98e37f8451SRapkiewicz, Pawel /**
99e37f8451SRapkiewicz, Pawel  * ChassisCollection derived class for delivering Chassis Collection Schema
100e37f8451SRapkiewicz, Pawel  */
101e37f8451SRapkiewicz, Pawel class ChassisCollection : public Node {
102e37f8451SRapkiewicz, Pawel  public:
103e37f8451SRapkiewicz, Pawel   ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") {
104e37f8451SRapkiewicz, Pawel     Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
105e37f8451SRapkiewicz, Pawel     Node::json["@odata.id"] = "/redfish/v1/Chassis";
106e37f8451SRapkiewicz, Pawel     Node::json["@odata.context"] =
107e37f8451SRapkiewicz, Pawel         "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
108e37f8451SRapkiewicz, Pawel     Node::json["Name"] = "Chassis Collection";
109e37f8451SRapkiewicz, Pawel 
110e0d918bcSEd Tanous     entityPrivileges = {
111e0d918bcSEd Tanous         {boost::beast::http::verb::get, {{"Login"}}},
112e0d918bcSEd Tanous         {boost::beast::http::verb::head, {{"Login"}}},
113e0d918bcSEd Tanous         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
114e0d918bcSEd Tanous         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
115e0d918bcSEd Tanous         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
116e0d918bcSEd Tanous         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
117e37f8451SRapkiewicz, Pawel   }
118e37f8451SRapkiewicz, Pawel 
119e37f8451SRapkiewicz, Pawel  private:
120e37f8451SRapkiewicz, Pawel   /**
121e37f8451SRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
122e37f8451SRapkiewicz, Pawel    */
12355c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
124e37f8451SRapkiewicz, Pawel              const std::vector<std::string> &params) override {
12555c7b7a2SEd Tanous     // get chassis list, and call the below callback for JSON preparation
12655c7b7a2SEd Tanous     chassisProvider.getChassisList(
127e37f8451SRapkiewicz, Pawel         [&](const bool &success, const std::vector<std::string> &output) {
128e37f8451SRapkiewicz, Pawel           if (success) {
129e37f8451SRapkiewicz, Pawel             // ... prepare json array with appropriate @odata.id links
13055c7b7a2SEd Tanous             nlohmann::json chassisArray = nlohmann::json::array();
13155c7b7a2SEd Tanous             for (const std::string &chassisItem : output) {
13255c7b7a2SEd Tanous               chassisArray.push_back(
13355c7b7a2SEd Tanous                   {{"@odata.id", "/redfish/v1/Chassis/" + chassisItem}});
134e37f8451SRapkiewicz, Pawel             }
135e37f8451SRapkiewicz, Pawel             // Then attach members, count size and return,
13655c7b7a2SEd Tanous             Node::json["Members"] = chassisArray;
13755c7b7a2SEd Tanous             Node::json["Members@odata.count"] = chassisArray.size();
13855c7b7a2SEd Tanous             res.jsonValue = Node::json;
139e37f8451SRapkiewicz, Pawel           } else {
140e37f8451SRapkiewicz, Pawel             // ... otherwise, return INTERNALL ERROR
141e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
142e37f8451SRapkiewicz, Pawel           }
143e37f8451SRapkiewicz, Pawel           res.end();
144e37f8451SRapkiewicz, Pawel         });
145e37f8451SRapkiewicz, Pawel   }
146e37f8451SRapkiewicz, Pawel 
147e37f8451SRapkiewicz, Pawel   // Chassis Provider object
148e37f8451SRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
14955c7b7a2SEd Tanous   OnDemandChassisProvider chassisProvider;
150e37f8451SRapkiewicz, Pawel };
151e37f8451SRapkiewicz, Pawel 
152e37f8451SRapkiewicz, Pawel /**
153e37f8451SRapkiewicz, Pawel  * Chassis override class for delivering Chassis Schema
154e37f8451SRapkiewicz, Pawel  */
155e37f8451SRapkiewicz, Pawel class Chassis : public Node {
156e37f8451SRapkiewicz, Pawel  public:
157e37f8451SRapkiewicz, Pawel   Chassis(CrowApp &app)
158e37f8451SRapkiewicz, Pawel       : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) {
159e37f8451SRapkiewicz, Pawel     Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
160e37f8451SRapkiewicz, Pawel     Node::json["@odata.id"] = "/redfish/v1/Chassis";
161e37f8451SRapkiewicz, Pawel     Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
162e37f8451SRapkiewicz, Pawel     Node::json["Name"] = "Chassis Collection";
1636c233015SEd Tanous     Node::json["ChassisType"] = "RackMount";
164e37f8451SRapkiewicz, Pawel 
165e0d918bcSEd Tanous     entityPrivileges = {
166e0d918bcSEd Tanous         {boost::beast::http::verb::get, {{"Login"}}},
167e0d918bcSEd Tanous         {boost::beast::http::verb::head, {{"Login"}}},
168e0d918bcSEd Tanous         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
169e0d918bcSEd Tanous         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
170e0d918bcSEd Tanous         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
171e0d918bcSEd Tanous         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
172e37f8451SRapkiewicz, Pawel   }
173e37f8451SRapkiewicz, Pawel 
174e37f8451SRapkiewicz, Pawel  private:
175e37f8451SRapkiewicz, Pawel   /**
176e37f8451SRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
177e37f8451SRapkiewicz, Pawel    */
17855c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
179e37f8451SRapkiewicz, Pawel              const std::vector<std::string> &params) override {
180e37f8451SRapkiewicz, Pawel     // Check if there is required param, truly entering this shall be
181e37f8451SRapkiewicz, Pawel     // impossible.
182e37f8451SRapkiewicz, Pawel     if (params.size() != 1) {
183e0d918bcSEd Tanous       res.result(boost::beast::http::status::internal_server_error);
184e37f8451SRapkiewicz, Pawel       res.end();
185e37f8451SRapkiewicz, Pawel       return;
186e37f8451SRapkiewicz, Pawel     }
187e37f8451SRapkiewicz, Pawel 
18855c7b7a2SEd Tanous     res.jsonValue = Node::json;
18955c7b7a2SEd Tanous     const std::string &chassisId = params[0];
19055c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
19155c7b7a2SEd Tanous         [&res, chassisId(std::string(chassisId)) ](
192daf36e2eSEd Tanous             const boost::system::error_code error_code,
193daf36e2eSEd Tanous             const std::vector<std::pair<
194daf36e2eSEd Tanous                 std::string,
195daf36e2eSEd Tanous                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
196daf36e2eSEd Tanous                 &subtree) {
197daf36e2eSEd Tanous           if (error_code) {
19855c7b7a2SEd Tanous             res.jsonValue = {};
199e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
200e37f8451SRapkiewicz, Pawel             res.end();
201daf36e2eSEd Tanous             return;
202daf36e2eSEd Tanous           }
203daf36e2eSEd Tanous           // Iterate over all retrieved ObjectPaths.
204daf36e2eSEd Tanous           for (const std::pair<std::string,
205daf36e2eSEd Tanous                                std::vector<std::pair<std::string,
206daf36e2eSEd Tanous                                                      std::vector<std::string>>>>
207daf36e2eSEd Tanous                    &object : subtree) {
208daf36e2eSEd Tanous             const std::string &path = object.first;
209daf36e2eSEd Tanous             const std::vector<std::pair<std::string, std::vector<std::string>>>
210daf36e2eSEd Tanous                 &connectionNames = object.second;
211e0d918bcSEd Tanous 
21255c7b7a2SEd Tanous             if (!boost::ends_with(path, chassisId)) {
213daf36e2eSEd Tanous               continue;
214daf36e2eSEd Tanous             }
215daf36e2eSEd Tanous             if (connectionNames.size() < 1) {
21655c7b7a2SEd Tanous               BMCWEB_LOG_ERROR << "Only got " << connectionNames.size()
21755c7b7a2SEd Tanous                                << " Connection names";
218e0d918bcSEd Tanous               continue;
219daf36e2eSEd Tanous             }
220e0d918bcSEd Tanous 
221daf36e2eSEd Tanous             const std::string connectionName = connectionNames[0].first;
22255c7b7a2SEd Tanous             crow::connections::systemBus->async_method_call(
22355c7b7a2SEd Tanous                 [&res, chassisId(std::string(chassisId)) ](
224daf36e2eSEd Tanous                     const boost::system::error_code error_code,
225daf36e2eSEd Tanous                     const std::vector<std::pair<std::string, VariantType>>
226daf36e2eSEd Tanous                         &propertiesList) {
227daf36e2eSEd Tanous                   for (const std::pair<std::string, VariantType> &property :
228daf36e2eSEd Tanous                        propertiesList) {
229daf36e2eSEd Tanous                     const std::string *value =
23055c7b7a2SEd Tanous                         mapbox::getPtr<const std::string>(property.second);
231daf36e2eSEd Tanous                     if (value != nullptr) {
23255c7b7a2SEd Tanous                       res.jsonValue[property.first] = *value;
233daf36e2eSEd Tanous                     }
234daf36e2eSEd Tanous                   }
23555c7b7a2SEd Tanous                   res.jsonValue["Name"] = chassisId;
23655c7b7a2SEd Tanous                   res.jsonValue["Id"] = chassisId;
23755c7b7a2SEd Tanous                   res.jsonValue["Thermal"] = {
238daf36e2eSEd Tanous                       {"@odata.id",
23955c7b7a2SEd Tanous                        "/redfish/v1/Chassis/" + chassisId + "/Thermal"}};
240daf36e2eSEd Tanous                   res.end();
241daf36e2eSEd Tanous                 },
242daf36e2eSEd Tanous                 connectionName, path, "org.freedesktop.DBus.Properties",
243daf36e2eSEd Tanous                 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
24455c7b7a2SEd Tanous             // Found the Connection we were looking for, return
245daf36e2eSEd Tanous             return;
246daf36e2eSEd Tanous           }
247e0d918bcSEd Tanous 
248daf36e2eSEd Tanous           // Couldn't find an object with that name.  return an error
249e0d918bcSEd Tanous           res.result(boost::beast::http::status::not_found);
250e0d918bcSEd Tanous 
251daf36e2eSEd Tanous           res.end();
252daf36e2eSEd Tanous         },
253daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper",
254daf36e2eSEd Tanous         "/xyz/openbmc_project/object_mapper",
255daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
256daf36e2eSEd Tanous         "/xyz/openbmc_project/inventory", int32_t(0),
257daf36e2eSEd Tanous         std::array<const char *, 1>{
258daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Decorator.Asset"});
259e37f8451SRapkiewicz, Pawel   }
260e37f8451SRapkiewicz, Pawel 
261e37f8451SRapkiewicz, Pawel   // Chassis Provider object
262e37f8451SRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
26355c7b7a2SEd Tanous   OnDemandChassisProvider chassisProvider;
264e0d918bcSEd Tanous };  // namespace redfish
265e37f8451SRapkiewicz, Pawel 
266e37f8451SRapkiewicz, Pawel }  // namespace redfish
267