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