xref: /openbmc/bmcweb/redfish-core/lib/chassis.hpp (revision aee8d847dc4d46030aa016818e5d0dc9d62feae4)
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         Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
49         Node::json["@odata.id"] = "/redfish/v1/Chassis";
50         Node::json["@odata.context"] =
51             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
52         Node::json["Name"] = "Chassis Collection";
53 
54         entityPrivileges = {
55             {boost::beast::http::verb::get, {{"Login"}}},
56             {boost::beast::http::verb::head, {{"Login"}}},
57             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
58             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
59             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
60             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
61     }
62 
63   private:
64     /**
65      * Functions triggers appropriate requests on DBus
66      */
67     void doGet(crow::Response &res, const crow::Request &req,
68                const std::vector<std::string> &params) override
69     {
70         const std::array<const char *, 4> interfaces = {
71             "xyz.openbmc_project.Inventory.Item.Board",
72             "xyz.openbmc_project.Inventory.Item.Chassis",
73             "xyz.openbmc_project.Inventory.Item.PowerSupply",
74             "xyz.openbmc_project.Inventory.Item.System",
75         };
76         res.jsonValue = Node::json;
77         auto asyncResp = std::make_shared<AsyncResp>(res);
78         crow::connections::systemBus->async_method_call(
79             [asyncResp](const boost::system::error_code ec,
80                         const std::vector<std::string> &chassisList) {
81                 if (ec)
82                 {
83                     messages::internalError(asyncResp->res);
84                     return;
85                 }
86                 nlohmann::json &chassisArray =
87                     asyncResp->res.jsonValue["Members"];
88                 chassisArray = nlohmann::json::array();
89                 for (const std::string &objpath : chassisList)
90                 {
91                     std::size_t lastPos = objpath.rfind("/");
92                     if (lastPos == std::string::npos)
93                     {
94                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
95                         continue;
96                     }
97                     chassisArray.push_back(
98                         {{"@odata.id", "/redfish/v1/Chassis/" +
99                                            objpath.substr(lastPos + 1)}});
100                 }
101 
102                 asyncResp->res.jsonValue["Members@odata.count"] =
103                     chassisArray.size();
104             },
105             "xyz.openbmc_project.ObjectMapper",
106             "/xyz/openbmc_project/object_mapper",
107             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
108             "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
109     }
110 };
111 
112 /**
113  * Chassis override class for delivering Chassis Schema
114  */
115 class Chassis : public Node
116 {
117   public:
118     Chassis(CrowApp &app) :
119         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
120     {
121         Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
122         Node::json["@odata.id"] = "/redfish/v1/Chassis";
123         Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
124         Node::json["Name"] = "Chassis Collection";
125         Node::json["ChassisType"] = "RackMount";
126         Node::json["PowerState"] = "On";
127 
128         entityPrivileges = {
129             {boost::beast::http::verb::get, {{"Login"}}},
130             {boost::beast::http::verb::head, {{"Login"}}},
131             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
132             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
133             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
134             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
135     }
136 
137   private:
138     /**
139      * Functions triggers appropriate requests on DBus
140      */
141     void doGet(crow::Response &res, const crow::Request &req,
142                const std::vector<std::string> &params) override
143     {
144         // Check if there is required param, truly entering this shall be
145         // impossible.
146         if (params.size() != 1)
147         {
148             messages::internalError(res);
149             res.end();
150             return;
151         }
152 
153         res.jsonValue = Node::json;
154         const std::string &chassisId = params[0];
155         auto asyncResp = std::make_shared<AsyncResp>(res);
156         crow::connections::systemBus->async_method_call(
157             [asyncResp, chassisId(std::string(chassisId))](
158                 const boost::system::error_code ec,
159                 const std::vector<std::pair<
160                     std::string, std::vector<std::pair<
161                                      std::string, std::vector<std::string>>>>>
162                     &subtree) {
163                 if (ec)
164                 {
165                     messages::internalError(asyncResp->res);
166                     return;
167                 }
168                 // Iterate over all retrieved ObjectPaths.
169                 for (const std::pair<
170                          std::string,
171                          std::vector<
172                              std::pair<std::string, std::vector<std::string>>>>
173                          &object : subtree)
174                 {
175                     const std::string &path = object.first;
176                     const std::vector<
177                         std::pair<std::string, std::vector<std::string>>>
178                         &connectionNames = object.second;
179 
180                     if (!boost::ends_with(path, chassisId))
181                     {
182                         continue;
183                     }
184                     if (connectionNames.size() < 1)
185                     {
186                         BMCWEB_LOG_ERROR << "Only got "
187                                          << connectionNames.size()
188                                          << " Connection names";
189                         continue;
190                     }
191 
192                     const std::string connectionName = connectionNames[0].first;
193                     crow::connections::systemBus->async_method_call(
194                         [asyncResp, chassisId(std::string(chassisId))](
195                             const boost::system::error_code ec,
196                             const std::vector<std::pair<
197                                 std::string, VariantType>> &propertiesList) {
198                             for (const std::pair<std::string, VariantType>
199                                      &property : propertiesList)
200                             {
201                                 const std::string *value =
202                                     mapbox::getPtr<const std::string>(
203                                         property.second);
204                                 if (value != nullptr)
205                                 {
206                                     asyncResp->res.jsonValue[property.first] =
207                                         *value;
208                                 }
209                             }
210                             asyncResp->res.jsonValue["Name"] = chassisId;
211                             asyncResp->res.jsonValue["Id"] = chassisId;
212                             asyncResp->res.jsonValue["Thermal"] = {
213                                 {"@odata.id", "/redfish/v1/Chassis/" +
214                                                   chassisId + "/Thermal"}};
215                             // Power object
216                             asyncResp->res.jsonValue["Power"] = {
217                                 {"@odata.id", "/redfish/v1/Chassis/" +
218                                                   chassisId + "/Power"}};
219 
220                             // TODO: An array of references to computer systems
221                             // contained in this chassis.
222                             // res.jsonValue["Links"]["ComputerSystems"]
223                             // =
224                             //                          {{{"@odata.id",
225                             //                          "/redfish/v1/Systems/1"}}};
226                             // An array of references to the Managers
227                             // responsible for managing this chassis.
228                             // res.jsonValue["Links"]["ManagedBy"] =
229                             //                        {{{"@odata.id",
230                             //                        "/redfish/v1/Managers/1"}}};
231                         },
232                         connectionName, path, "org.freedesktop.DBus.Properties",
233                         "GetAll",
234                         "xyz.openbmc_project.Inventory.Decorator.Asset");
235                     return;
236                 }
237 
238                 // Couldn't find an object with that name.  return an error
239                 messages::resourceNotFound(
240                     asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
241             },
242             "xyz.openbmc_project.ObjectMapper",
243             "/xyz/openbmc_project/object_mapper",
244             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
245             "/xyz/openbmc_project/inventory", int32_t(0),
246             std::array<const char *, 1>{
247                 "xyz.openbmc_project.Inventory.Decorator.Asset"});
248     }
249 };
250 } // namespace redfish
251