xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision c5b2abe0d218d0decd7f1617f870ec67c6b7dd5f)
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  */
27aa2e59c1SEd 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
30*c5b2abe0SLewanczyk, 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>
58e37f8451SRapkiewicz, Pawel   void get_chassis_list(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     };
65e37f8451SRapkiewicz, Pawel     crow::connections::system_bus->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.
71e37f8451SRapkiewicz, Pawel           std::vector<std::string> chassis_list;
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.
77e37f8451SRapkiewicz, Pawel             callback(false, chassis_list);
78e37f8451SRapkiewicz, Pawel             return;
79e37f8451SRapkiewicz, Pawel           }
80e37f8451SRapkiewicz, Pawel           // Iterate over all retrieved ObjectPaths.
81daf36e2eSEd Tanous           for (const std::string &objpath : resp) {
82daf36e2eSEd Tanous             std::size_t last_pos = objpath.rfind("/");
83e37f8451SRapkiewicz, Pawel             if (last_pos != std::string::npos) {
84e37f8451SRapkiewicz, Pawel               // and put it into output vector.
85daf36e2eSEd Tanous               chassis_list.emplace_back(objpath.substr(last_pos + 1));
86e37f8451SRapkiewicz, Pawel             }
87e37f8451SRapkiewicz, Pawel           }
88274fad5aSGunnar Mills           // Finally make a callback with useful data
89e37f8451SRapkiewicz, Pawel           callback(true, chassis_list);
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   template <typename CrowApp>
104e37f8451SRapkiewicz, Pawel   ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") {
105e37f8451SRapkiewicz, Pawel     Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
106e37f8451SRapkiewicz, Pawel     Node::json["@odata.id"] = "/redfish/v1/Chassis";
107e37f8451SRapkiewicz, Pawel     Node::json["@odata.context"] =
108e37f8451SRapkiewicz, Pawel         "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
109e37f8451SRapkiewicz, Pawel     Node::json["Name"] = "Chassis Collection";
110e37f8451SRapkiewicz, Pawel 
111e0d918bcSEd Tanous     entityPrivileges = {
112e0d918bcSEd Tanous         {boost::beast::http::verb::get, {{"Login"}}},
113e0d918bcSEd Tanous         {boost::beast::http::verb::head, {{"Login"}}},
114e0d918bcSEd Tanous         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
115e0d918bcSEd Tanous         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
116e0d918bcSEd Tanous         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
117e0d918bcSEd Tanous         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
118e37f8451SRapkiewicz, Pawel   }
119e37f8451SRapkiewicz, Pawel 
120e37f8451SRapkiewicz, Pawel  private:
121e37f8451SRapkiewicz, Pawel   /**
122e37f8451SRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
123e37f8451SRapkiewicz, Pawel    */
124e37f8451SRapkiewicz, Pawel   void doGet(crow::response &res, const crow::request &req,
125e37f8451SRapkiewicz, Pawel              const std::vector<std::string> &params) override {
126e37f8451SRapkiewicz, Pawel     // Get chassis list, and call the below callback for JSON preparation
127e37f8451SRapkiewicz, Pawel     chassis_provider.get_chassis_list(
128e37f8451SRapkiewicz, Pawel         [&](const bool &success, const std::vector<std::string> &output) {
129e37f8451SRapkiewicz, Pawel           if (success) {
130e37f8451SRapkiewicz, Pawel             // ... prepare json array with appropriate @odata.id links
131e37f8451SRapkiewicz, Pawel             nlohmann::json chassis_array = nlohmann::json::array();
132e37f8451SRapkiewicz, Pawel             for (const std::string &chassis_item : output) {
133e37f8451SRapkiewicz, Pawel               chassis_array.push_back(
134e37f8451SRapkiewicz, Pawel                   {{"@odata.id", "/redfish/v1/Chassis/" + chassis_item}});
135e37f8451SRapkiewicz, Pawel             }
136e37f8451SRapkiewicz, Pawel             // Then attach members, count size and return,
137e37f8451SRapkiewicz, Pawel             Node::json["Members"] = chassis_array;
138e37f8451SRapkiewicz, Pawel             Node::json["Members@odata.count"] = chassis_array.size();
139e37f8451SRapkiewicz, Pawel             res.json_value = Node::json;
140e37f8451SRapkiewicz, Pawel           } else {
141e37f8451SRapkiewicz, Pawel             // ... otherwise, return INTERNALL ERROR
142e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
143e37f8451SRapkiewicz, Pawel           }
144e37f8451SRapkiewicz, Pawel           res.end();
145e37f8451SRapkiewicz, Pawel         });
146e37f8451SRapkiewicz, Pawel   }
147e37f8451SRapkiewicz, Pawel 
148e37f8451SRapkiewicz, Pawel   // Chassis Provider object
149e37f8451SRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
150e37f8451SRapkiewicz, Pawel   OnDemandChassisProvider chassis_provider;
151e37f8451SRapkiewicz, Pawel };
152e37f8451SRapkiewicz, Pawel 
153e37f8451SRapkiewicz, Pawel /**
154e37f8451SRapkiewicz, Pawel  * Chassis override class for delivering Chassis Schema
155e37f8451SRapkiewicz, Pawel  */
156e37f8451SRapkiewicz, Pawel class Chassis : public Node {
157e37f8451SRapkiewicz, Pawel  public:
158e37f8451SRapkiewicz, Pawel   /*
159e37f8451SRapkiewicz, Pawel    * Default Constructor
160e37f8451SRapkiewicz, Pawel    */
161e37f8451SRapkiewicz, Pawel   template <typename CrowApp>
162e37f8451SRapkiewicz, Pawel   Chassis(CrowApp &app)
163e37f8451SRapkiewicz, Pawel       : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) {
164e37f8451SRapkiewicz, Pawel     Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
165e37f8451SRapkiewicz, Pawel     Node::json["@odata.id"] = "/redfish/v1/Chassis";
166e37f8451SRapkiewicz, Pawel     Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
167e37f8451SRapkiewicz, Pawel     Node::json["Name"] = "Chassis Collection";
1686c233015SEd Tanous     Node::json["ChassisType"] = "RackMount";
169e37f8451SRapkiewicz, Pawel 
170e0d918bcSEd Tanous     entityPrivileges = {
171e0d918bcSEd Tanous         {boost::beast::http::verb::get, {{"Login"}}},
172e0d918bcSEd Tanous         {boost::beast::http::verb::head, {{"Login"}}},
173e0d918bcSEd Tanous         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
174e0d918bcSEd Tanous         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
175e0d918bcSEd Tanous         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
176e0d918bcSEd Tanous         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
177e37f8451SRapkiewicz, Pawel   }
178e37f8451SRapkiewicz, Pawel 
179e37f8451SRapkiewicz, Pawel  private:
180e37f8451SRapkiewicz, Pawel   /**
181e37f8451SRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
182e37f8451SRapkiewicz, Pawel    */
183e37f8451SRapkiewicz, Pawel   void doGet(crow::response &res, const crow::request &req,
184e37f8451SRapkiewicz, Pawel              const std::vector<std::string> &params) override {
185e37f8451SRapkiewicz, Pawel     // Check if there is required param, truly entering this shall be
186e37f8451SRapkiewicz, Pawel     // impossible.
187e37f8451SRapkiewicz, Pawel     if (params.size() != 1) {
188e0d918bcSEd Tanous       res.result(boost::beast::http::status::internal_server_error);
189e37f8451SRapkiewicz, Pawel       res.end();
190e37f8451SRapkiewicz, Pawel       return;
191e37f8451SRapkiewicz, Pawel     }
192e37f8451SRapkiewicz, Pawel 
193daf36e2eSEd Tanous     res.json_value = Node::json;
194daf36e2eSEd Tanous     const std::string &chassis_id = params[0];
195daf36e2eSEd Tanous     crow::connections::system_bus->async_method_call(
196daf36e2eSEd Tanous         [&res, chassis_id(std::string(chassis_id)) ](
197daf36e2eSEd Tanous             const boost::system::error_code error_code,
198daf36e2eSEd Tanous             const std::vector<std::pair<
199daf36e2eSEd Tanous                 std::string,
200daf36e2eSEd Tanous                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
201daf36e2eSEd Tanous                 &subtree) {
202daf36e2eSEd Tanous           if (error_code) {
203daf36e2eSEd Tanous             res.json_value = {};
204e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
205e37f8451SRapkiewicz, Pawel             res.end();
206daf36e2eSEd Tanous             return;
207daf36e2eSEd Tanous           }
208daf36e2eSEd Tanous           // Iterate over all retrieved ObjectPaths.
209daf36e2eSEd Tanous           for (const std::pair<std::string,
210daf36e2eSEd Tanous                                std::vector<std::pair<std::string,
211daf36e2eSEd Tanous                                                      std::vector<std::string>>>>
212daf36e2eSEd Tanous                    &object : subtree) {
213daf36e2eSEd Tanous             const std::string &path = object.first;
214daf36e2eSEd Tanous             const std::vector<std::pair<std::string, std::vector<std::string>>>
215daf36e2eSEd Tanous                 &connectionNames = object.second;
216e0d918bcSEd Tanous 
217daf36e2eSEd Tanous             if (!boost::ends_with(path, chassis_id)) {
218daf36e2eSEd Tanous               continue;
219daf36e2eSEd Tanous             }
220daf36e2eSEd Tanous             if (connectionNames.size() < 1) {
221e0d918bcSEd Tanous               CROW_LOG_ERROR << "Only got " << connectionNames.size()
222e0d918bcSEd Tanous                              << " connection names";
223e0d918bcSEd Tanous               continue;
224daf36e2eSEd Tanous             }
225e0d918bcSEd Tanous 
226daf36e2eSEd Tanous             const std::string connectionName = connectionNames[0].first;
227daf36e2eSEd Tanous             crow::connections::system_bus->async_method_call(
228daf36e2eSEd Tanous                 [&res, chassis_id(std::string(chassis_id)) ](
229daf36e2eSEd Tanous                     const boost::system::error_code error_code,
230daf36e2eSEd Tanous                     const std::vector<std::pair<std::string, VariantType>>
231daf36e2eSEd Tanous                         &propertiesList) {
232daf36e2eSEd Tanous                   for (const std::pair<std::string, VariantType> &property :
233daf36e2eSEd Tanous                        propertiesList) {
234daf36e2eSEd Tanous                     const std::string *value =
235daf36e2eSEd Tanous                         mapbox::get_ptr<const std::string>(property.second);
236daf36e2eSEd Tanous                     if (value != nullptr) {
237daf36e2eSEd Tanous                       res.json_value[property.first] = *value;
238daf36e2eSEd Tanous                     }
239daf36e2eSEd Tanous                   }
240daf36e2eSEd Tanous                   res.json_value["Name"] = chassis_id;
241daf36e2eSEd Tanous                   res.json_value["Thermal"] = {
242daf36e2eSEd Tanous                       {"@odata.id",
243daf36e2eSEd Tanous                        "/redfish/v1/Chassis/" + chassis_id + "/Thermal"}};
244daf36e2eSEd Tanous                   res.end();
245daf36e2eSEd Tanous                 },
246daf36e2eSEd Tanous                 connectionName, path, "org.freedesktop.DBus.Properties",
247daf36e2eSEd Tanous                 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
248daf36e2eSEd Tanous             // Found the connection we were looking for, return
249daf36e2eSEd Tanous             return;
250daf36e2eSEd Tanous           }
251e0d918bcSEd Tanous 
252daf36e2eSEd Tanous           // Couldn't find an object with that name.  return an error
253e0d918bcSEd Tanous           res.result(boost::beast::http::status::not_found);
254e0d918bcSEd Tanous 
255daf36e2eSEd Tanous           res.end();
256daf36e2eSEd Tanous         },
257daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper",
258daf36e2eSEd Tanous         "/xyz/openbmc_project/object_mapper",
259daf36e2eSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
260daf36e2eSEd Tanous         "/xyz/openbmc_project/inventory", int32_t(0),
261daf36e2eSEd Tanous         std::array<const char *, 1>{
262daf36e2eSEd Tanous             "xyz.openbmc_project.Inventory.Decorator.Asset"});
263e37f8451SRapkiewicz, Pawel   }
264e37f8451SRapkiewicz, Pawel 
265e37f8451SRapkiewicz, Pawel   // Chassis Provider object
266e37f8451SRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
267e37f8451SRapkiewicz, Pawel   OnDemandChassisProvider chassis_provider;
268e0d918bcSEd Tanous };  // namespace redfish
269e37f8451SRapkiewicz, Pawel 
270e37f8451SRapkiewicz, Pawel }  // namespace redfish
271