xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 029573d4d59ce5a67e4713a261b703f6cadfd8ef)
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 #include <variant>
22 
23 namespace redfish
24 {
25 
26 /**
27  * DBus types primitives for several generic DBus interfaces
28  * TODO(Pawel) consider move this to separate file into boost::dbus
29  */
30 // Note, this is not a very useful Variant, but because it isn't used to get
31 // values, it should be as simple as possible
32 // TODO(ed) invent a nullvariant type
33 using VariantType = std::variant<bool, std::string, uint64_t>;
34 using ManagedObjectsType = std::vector<std::pair<
35     sdbusplus::message::object_path,
36     std::vector<std::pair<std::string,
37                           std::vector<std::pair<std::string, VariantType>>>>>>;
38 
39 using PropertiesType = boost::container::flat_map<std::string, VariantType>;
40 
41 /**
42  * ChassisCollection derived class for delivering Chassis Collection Schema
43  */
44 class ChassisCollection : public Node
45 {
46   public:
47     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
48     {
49         entityPrivileges = {
50             {boost::beast::http::verb::get, {{"Login"}}},
51             {boost::beast::http::verb::head, {{"Login"}}},
52             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
53             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
54             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
55             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
56     }
57 
58   private:
59     /**
60      * Functions triggers appropriate requests on DBus
61      */
62     void doGet(crow::Response &res, const crow::Request &req,
63                const std::vector<std::string> &params) override
64     {
65         const std::array<const char *, 3> interfaces = {
66             "xyz.openbmc_project.Inventory.Item.Board",
67             "xyz.openbmc_project.Inventory.Item.Chassis",
68             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
69         res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
70         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
71         res.jsonValue["@odata.context"] =
72             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
73         res.jsonValue["Name"] = "Chassis Collection";
74 
75         auto asyncResp = std::make_shared<AsyncResp>(res);
76         crow::connections::systemBus->async_method_call(
77             [asyncResp](const boost::system::error_code ec,
78                         const std::vector<std::string> &chassisList) {
79                 if (ec)
80                 {
81                     messages::internalError(asyncResp->res);
82                     return;
83                 }
84                 nlohmann::json &chassisArray =
85                     asyncResp->res.jsonValue["Members"];
86                 chassisArray = nlohmann::json::array();
87                 for (const std::string &objpath : chassisList)
88                 {
89                     std::size_t lastPos = objpath.rfind("/");
90                     if (lastPos == std::string::npos)
91                     {
92                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
93                         continue;
94                     }
95                     chassisArray.push_back(
96                         {{"@odata.id", "/redfish/v1/Chassis/" +
97                                            objpath.substr(lastPos + 1)}});
98                 }
99 
100                 asyncResp->res.jsonValue["Members@odata.count"] =
101                     chassisArray.size();
102             },
103             "xyz.openbmc_project.ObjectMapper",
104             "/xyz/openbmc_project/object_mapper",
105             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
106             "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
107     }
108 };
109 
110 /**
111  * Chassis override class for delivering Chassis Schema
112  */
113 class Chassis : public Node
114 {
115   public:
116     Chassis(CrowApp &app) :
117         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
118     {
119         entityPrivileges = {
120             {boost::beast::http::verb::get, {{"Login"}}},
121             {boost::beast::http::verb::head, {{"Login"}}},
122             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
123             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
124             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
125             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
126     }
127 
128   private:
129     /**
130      * Functions triggers appropriate requests on DBus
131      */
132     void doGet(crow::Response &res, const crow::Request &req,
133                const std::vector<std::string> &params) override
134     {
135         const std::array<const char *, 3> interfaces = {
136             "xyz.openbmc_project.Inventory.Item.Board",
137             "xyz.openbmc_project.Inventory.Item.Chassis",
138             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
139 
140         // Check if there is required param, truly entering this shall be
141         // impossible.
142         if (params.size() != 1)
143         {
144             messages::internalError(res);
145             res.end();
146             return;
147         }
148 
149         res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
150         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
151         res.jsonValue["@odata.context"] =
152             "/redfish/v1/$metadata#Chassis.Chassis";
153         res.jsonValue["Name"] = "Chassis Collection";
154         res.jsonValue["ChassisType"] = "RackMount";
155         res.jsonValue["PowerState"] = "On";
156 
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::internalError(asyncResp->res);
169                     return;
170                 }
171                 // Iterate over all retrieved ObjectPaths.
172                 for (const std::pair<
173                          std::string,
174                          std::vector<
175                              std::pair<std::string, std::vector<std::string>>>>
176                          &object : subtree)
177                 {
178                     const std::string &path = object.first;
179                     const std::vector<
180                         std::pair<std::string, std::vector<std::string>>>
181                         &connectionNames = object.second;
182 
183                     if (!boost::ends_with(path, chassisId))
184                     {
185                         continue;
186                     }
187                     if (connectionNames.size() < 1)
188                     {
189                         BMCWEB_LOG_ERROR << "Only got "
190                                          << connectionNames.size()
191                                          << " Connection names";
192                         continue;
193                     }
194 
195                     const std::string connectionName = connectionNames[0].first;
196                     crow::connections::systemBus->async_method_call(
197                         [asyncResp, chassisId(std::string(chassisId))](
198                             const boost::system::error_code ec,
199                             const std::vector<std::pair<
200                                 std::string, VariantType>> &propertiesList) {
201                             for (const std::pair<std::string, VariantType>
202                                      &property : propertiesList)
203                             {
204                                 const std::string *value =
205                                     std::get_if<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                             asyncResp->res.jsonValue["Status"] = {
222                                 {"Health", "OK"},
223                                 {"State", "Enabled"},
224                             };
225 
226                             asyncResp->res
227                                 .jsonValue["Links"]["ComputerSystems"] = {
228                                 {{"@odata.id", "/redfish/v1/Systems/system"}}};
229                             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
230                                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
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), interfaces);
246     }
247 };
248 } // namespace redfish
249