xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 734bfe90949b230b1d3e061522f45903c10c7b08)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "node.hpp"
19 
20 #include <boost/container/flat_map.hpp>
21 
22 namespace redfish
23 {
24 
25 /**
26  * DBus types primitives for several generic DBus interfaces
27  * TODO(Pawel) consider move this to separate file into boost::dbus
28  */
29 // Note, this is not a very useful Variant, but because it isn't used to get
30 // values, it should be as simple as possible
31 // TODO(ed) invent a nullvariant type
32 using VariantType = sdbusplus::message::variant<bool, std::string, uint64_t>;
33 using ManagedObjectsType = std::vector<std::pair<
34     sdbusplus::message::object_path,
35     std::vector<std::pair<std::string,
36                           std::vector<std::pair<std::string, VariantType>>>>>>;
37 
38 using PropertiesType = boost::container::flat_map<std::string, VariantType>;
39 
40 /**
41  * ChassisCollection derived class for delivering Chassis Collection Schema
42  */
43 class ChassisCollection : public Node
44 {
45   public:
46     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
47     {
48         entityPrivileges = {
49             {boost::beast::http::verb::get, {{"Login"}}},
50             {boost::beast::http::verb::head, {{"Login"}}},
51             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
52             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
53             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
54             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
55     }
56 
57   private:
58     /**
59      * Functions triggers appropriate requests on DBus
60      */
61     void doGet(crow::Response &res, const crow::Request &req,
62                const std::vector<std::string> &params) override
63     {
64         const std::array<const char *, 3> interfaces = {
65             "xyz.openbmc_project.Inventory.Item.Board",
66             "xyz.openbmc_project.Inventory.Item.Chassis",
67             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
68         res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
69         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
70         res.jsonValue["@odata.context"] =
71             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
72         res.jsonValue["Name"] = "Chassis Collection";
73 
74         auto asyncResp = std::make_shared<AsyncResp>(res);
75         crow::connections::systemBus->async_method_call(
76             [asyncResp](const boost::system::error_code ec,
77                         const std::vector<std::string> &chassisList) {
78                 if (ec)
79                 {
80                     messages::internalError(asyncResp->res);
81                     return;
82                 }
83                 nlohmann::json &chassisArray =
84                     asyncResp->res.jsonValue["Members"];
85                 chassisArray = nlohmann::json::array();
86                 for (const std::string &objpath : chassisList)
87                 {
88                     std::size_t lastPos = objpath.rfind("/");
89                     if (lastPos == std::string::npos)
90                     {
91                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
92                         continue;
93                     }
94                     chassisArray.push_back(
95                         {{"@odata.id", "/redfish/v1/Chassis/" +
96                                            objpath.substr(lastPos + 1)}});
97                 }
98 
99                 asyncResp->res.jsonValue["Members@odata.count"] =
100                     chassisArray.size();
101             },
102             "xyz.openbmc_project.ObjectMapper",
103             "/xyz/openbmc_project/object_mapper",
104             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
105             "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
106     }
107 };
108 
109 /**
110  * Chassis override class for delivering Chassis Schema
111  */
112 class Chassis : public Node
113 {
114   public:
115     Chassis(CrowApp &app) :
116         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
117     {
118         entityPrivileges = {
119             {boost::beast::http::verb::get, {{"Login"}}},
120             {boost::beast::http::verb::head, {{"Login"}}},
121             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
122             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
123             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
124             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
125     }
126 
127   private:
128     /**
129      * Functions triggers appropriate requests on DBus
130      */
131     void doGet(crow::Response &res, const crow::Request &req,
132                const std::vector<std::string> &params) override
133     {
134         const std::array<const char *, 3> interfaces = {
135             "xyz.openbmc_project.Inventory.Item.Board",
136             "xyz.openbmc_project.Inventory.Item.Chassis",
137             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
138 
139         // Check if there is required param, truly entering this shall be
140         // impossible.
141         if (params.size() != 1)
142         {
143             messages::internalError(res);
144             res.end();
145             return;
146         }
147 
148         res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
149         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
150         res.jsonValue["@odata.context"] =
151             "/redfish/v1/$metadata#Chassis.Chassis";
152         res.jsonValue["Name"] = "Chassis Collection";
153         res.jsonValue["ChassisType"] = "RackMount";
154         res.jsonValue["PowerState"] = "On";
155 
156         const std::string &chassisId = params[0];
157         auto asyncResp = std::make_shared<AsyncResp>(res);
158         crow::connections::systemBus->async_method_call(
159             [asyncResp, chassisId(std::string(chassisId))](
160                 const boost::system::error_code ec,
161                 const std::vector<std::pair<
162                     std::string, std::vector<std::pair<
163                                      std::string, std::vector<std::string>>>>>
164                     &subtree) {
165                 if (ec)
166                 {
167                     messages::internalError(asyncResp->res);
168                     return;
169                 }
170                 // Iterate over all retrieved ObjectPaths.
171                 for (const std::pair<
172                          std::string,
173                          std::vector<
174                              std::pair<std::string, std::vector<std::string>>>>
175                          &object : subtree)
176                 {
177                     const std::string &path = object.first;
178                     const std::vector<
179                         std::pair<std::string, std::vector<std::string>>>
180                         &connectionNames = object.second;
181 
182                     if (!boost::ends_with(path, chassisId))
183                     {
184                         continue;
185                     }
186                     if (connectionNames.size() < 1)
187                     {
188                         BMCWEB_LOG_ERROR << "Only got "
189                                          << connectionNames.size()
190                                          << " Connection names";
191                         continue;
192                     }
193 
194                     const std::string connectionName = connectionNames[0].first;
195                     crow::connections::systemBus->async_method_call(
196                         [asyncResp, chassisId(std::string(chassisId))](
197                             const boost::system::error_code ec,
198                             const std::vector<std::pair<
199                                 std::string, VariantType>> &propertiesList) {
200                             for (const std::pair<std::string, VariantType>
201                                      &property : propertiesList)
202                             {
203                                 const std::string *value =
204                                     sdbusplus::message::variant_ns::get_if<
205                                         std::string>(&property.second);
206                                 if (value != nullptr)
207                                 {
208                                     asyncResp->res.jsonValue[property.first] =
209                                         *value;
210                                 }
211                             }
212                             asyncResp->res.jsonValue["Name"] = chassisId;
213                             asyncResp->res.jsonValue["Id"] = chassisId;
214                             asyncResp->res.jsonValue["Thermal"] = {
215                                 {"@odata.id", "/redfish/v1/Chassis/" +
216                                                   chassisId + "/Thermal"}};
217                             // Power object
218                             asyncResp->res.jsonValue["Power"] = {
219                                 {"@odata.id", "/redfish/v1/Chassis/" +
220                                                   chassisId + "/Power"}};
221 
222                             // TODO: An array of references to computer systems
223                             // contained in this chassis.
224                             // res.jsonValue["Links"]["ComputerSystems"]
225                             // =
226                             //                          {{{"@odata.id",
227                             //                          "/redfish/v1/Systems/1"}}};
228                             // An array of references to the Managers
229                             // responsible for managing this chassis.
230                             // res.jsonValue["Links"]["ManagedBy"] =
231                             //                        {{{"@odata.id",
232                             //                        "/redfish/v1/Managers/1"}}};
233                         },
234                         connectionName, path, "org.freedesktop.DBus.Properties",
235                         "GetAll",
236                         "xyz.openbmc_project.Inventory.Decorator.Asset");
237                     return;
238                 }
239 
240                 // Couldn't find an object with that name.  return an error
241                 messages::resourceNotFound(
242                     asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
243             },
244             "xyz.openbmc_project.ObjectMapper",
245             "/xyz/openbmc_project/object_mapper",
246             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
247             "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
248     }
249 };
250 } // namespace redfish
251