xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 04a258f40c26565b4042a32b5c9b5f2414dae0df)
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"
191abe55efSEd Tanous 
20e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp>
21e37f8451SRapkiewicz, Pawel 
221abe55efSEd Tanous namespace redfish
231abe55efSEd Tanous {
24e37f8451SRapkiewicz, Pawel 
25e37f8451SRapkiewicz, Pawel /**
26e37f8451SRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
27e37f8451SRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
28e37f8451SRapkiewicz, Pawel  */
2955c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get
30aa2e59c1SEd Tanous // values, it should be as simple as possible
31aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type
32*04a258f4SEd Tanous using VariantType = sdbusplus::message::variant<bool, std::string, uint64_t>;
33aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair<
34aa2e59c1SEd Tanous     sdbusplus::message::object_path,
35aa2e59c1SEd Tanous     std::vector<std::pair<std::string,
36aa2e59c1SEd Tanous                           std::vector<std::pair<std::string, VariantType>>>>>>;
37e37f8451SRapkiewicz, Pawel 
38aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>;
39e37f8451SRapkiewicz, Pawel 
40e37f8451SRapkiewicz, Pawel /**
41e37f8451SRapkiewicz, Pawel  * ChassisCollection derived class for delivering Chassis Collection Schema
42e37f8451SRapkiewicz, Pawel  */
431abe55efSEd Tanous class ChassisCollection : public Node
441abe55efSEd Tanous {
45e37f8451SRapkiewicz, Pawel   public:
461abe55efSEd Tanous     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
471abe55efSEd Tanous     {
48e37f8451SRapkiewicz, Pawel         Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
49e37f8451SRapkiewicz, Pawel         Node::json["@odata.id"] = "/redfish/v1/Chassis";
50e37f8451SRapkiewicz, Pawel         Node::json["@odata.context"] =
51e37f8451SRapkiewicz, Pawel             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
52e37f8451SRapkiewicz, Pawel         Node::json["Name"] = "Chassis Collection";
53e37f8451SRapkiewicz, Pawel 
54e0d918bcSEd Tanous         entityPrivileges = {
55e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
56e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
57e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
58e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
59e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
60e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
61e37f8451SRapkiewicz, Pawel     }
62e37f8451SRapkiewicz, Pawel 
63e37f8451SRapkiewicz, Pawel   private:
64e37f8451SRapkiewicz, Pawel     /**
65e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
66e37f8451SRapkiewicz, Pawel      */
6755c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
681abe55efSEd Tanous                const std::vector<std::string> &params) override
691abe55efSEd Tanous     {
7062d5e2e4SEd Tanous         const std::array<const char *, 4> interfaces = {
7162d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.Board",
7262d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.Chassis",
7362d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.PowerSupply",
7462d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.System",
7562d5e2e4SEd Tanous         };
7655c7b7a2SEd Tanous         res.jsonValue = Node::json;
7762d5e2e4SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
7862d5e2e4SEd Tanous         crow::connections::systemBus->async_method_call(
7962d5e2e4SEd Tanous             [asyncResp](const boost::system::error_code ec,
8062d5e2e4SEd Tanous                         const std::vector<std::string> &chassisList) {
8162d5e2e4SEd Tanous                 if (ec)
821abe55efSEd Tanous                 {
8362d5e2e4SEd Tanous                     messages::addMessageToErrorJson(asyncResp->res.jsonValue,
8462d5e2e4SEd Tanous                                                     messages::internalError());
8562d5e2e4SEd Tanous                     asyncResp->res.result(
861abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
8762d5e2e4SEd Tanous                     return;
88e37f8451SRapkiewicz, Pawel                 }
8962d5e2e4SEd Tanous                 nlohmann::json &chassisArray =
9062d5e2e4SEd Tanous                     asyncResp->res.jsonValue["Members"];
9162d5e2e4SEd Tanous                 chassisArray = nlohmann::json::array();
9262d5e2e4SEd Tanous                 for (const std::string &objpath : chassisList)
9362d5e2e4SEd Tanous                 {
9462d5e2e4SEd Tanous                     std::size_t lastPos = objpath.rfind("/");
9562d5e2e4SEd Tanous                     if (lastPos == std::string::npos)
9662d5e2e4SEd Tanous                     {
9762d5e2e4SEd Tanous                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
9862d5e2e4SEd Tanous                         continue;
9962d5e2e4SEd Tanous                     }
10062d5e2e4SEd Tanous                     chassisArray.push_back(
10162d5e2e4SEd Tanous                         {{"@odata.id", "/redfish/v1/Chassis/" +
10262d5e2e4SEd Tanous                                            objpath.substr(lastPos + 1)}});
103e37f8451SRapkiewicz, Pawel                 }
104e37f8451SRapkiewicz, Pawel 
10562d5e2e4SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
10662d5e2e4SEd Tanous                     chassisArray.size();
10762d5e2e4SEd Tanous             },
10862d5e2e4SEd Tanous             "xyz.openbmc_project.ObjectMapper",
10962d5e2e4SEd Tanous             "/xyz/openbmc_project/object_mapper",
11062d5e2e4SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
11162d5e2e4SEd Tanous             "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
11262d5e2e4SEd Tanous     }
113e37f8451SRapkiewicz, Pawel };
114e37f8451SRapkiewicz, Pawel 
115e37f8451SRapkiewicz, Pawel /**
116e37f8451SRapkiewicz, Pawel  * Chassis override class for delivering Chassis Schema
117e37f8451SRapkiewicz, Pawel  */
1181abe55efSEd Tanous class Chassis : public Node
1191abe55efSEd Tanous {
120e37f8451SRapkiewicz, Pawel   public:
1211abe55efSEd Tanous     Chassis(CrowApp &app) :
1221abe55efSEd Tanous         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
1231abe55efSEd Tanous     {
124e37f8451SRapkiewicz, Pawel         Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
125e37f8451SRapkiewicz, Pawel         Node::json["@odata.id"] = "/redfish/v1/Chassis";
126e37f8451SRapkiewicz, Pawel         Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
127e37f8451SRapkiewicz, Pawel         Node::json["Name"] = "Chassis Collection";
1286c233015SEd Tanous         Node::json["ChassisType"] = "RackMount";
129e37f8451SRapkiewicz, Pawel 
130e0d918bcSEd Tanous         entityPrivileges = {
131e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
132e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
133e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
134e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
135e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
136e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
137e37f8451SRapkiewicz, Pawel     }
138e37f8451SRapkiewicz, Pawel 
139e37f8451SRapkiewicz, Pawel   private:
140e37f8451SRapkiewicz, Pawel     /**
141e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
142e37f8451SRapkiewicz, Pawel      */
14355c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1441abe55efSEd Tanous                const std::vector<std::string> &params) override
1451abe55efSEd Tanous     {
146e37f8451SRapkiewicz, Pawel         // Check if there is required param, truly entering this shall be
147e37f8451SRapkiewicz, Pawel         // impossible.
1481abe55efSEd Tanous         if (params.size() != 1)
1491abe55efSEd Tanous         {
150e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
151e37f8451SRapkiewicz, Pawel             res.end();
152e37f8451SRapkiewicz, Pawel             return;
153e37f8451SRapkiewicz, Pawel         }
154e37f8451SRapkiewicz, Pawel 
15555c7b7a2SEd Tanous         res.jsonValue = Node::json;
15655c7b7a2SEd Tanous         const std::string &chassisId = params[0];
15762d5e2e4SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
15855c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
15962d5e2e4SEd Tanous             [asyncResp, chassisId(std::string(chassisId))](
16062d5e2e4SEd Tanous                 const boost::system::error_code ec,
161daf36e2eSEd Tanous                 const std::vector<std::pair<
1621abe55efSEd Tanous                     std::string, std::vector<std::pair<
1631abe55efSEd Tanous                                      std::string, std::vector<std::string>>>>>
164daf36e2eSEd Tanous                     &subtree) {
16562d5e2e4SEd Tanous                 if (ec)
1661abe55efSEd Tanous                 {
16762d5e2e4SEd Tanous                     messages::addMessageToErrorJson(asyncResp->res.jsonValue,
16862d5e2e4SEd Tanous                                                     messages::internalError());
16962d5e2e4SEd Tanous                     asyncResp->res.result(
1701abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
171daf36e2eSEd Tanous                     return;
172daf36e2eSEd Tanous                 }
173daf36e2eSEd Tanous                 // Iterate over all retrieved ObjectPaths.
1741abe55efSEd Tanous                 for (const std::pair<
1751abe55efSEd Tanous                          std::string,
1761abe55efSEd Tanous                          std::vector<
1771abe55efSEd Tanous                              std::pair<std::string, std::vector<std::string>>>>
1781abe55efSEd Tanous                          &object : subtree)
1791abe55efSEd Tanous                 {
180daf36e2eSEd Tanous                     const std::string &path = object.first;
1811abe55efSEd Tanous                     const std::vector<
1821abe55efSEd Tanous                         std::pair<std::string, std::vector<std::string>>>
183daf36e2eSEd Tanous                         &connectionNames = object.second;
184e0d918bcSEd Tanous 
1851abe55efSEd Tanous                     if (!boost::ends_with(path, chassisId))
1861abe55efSEd Tanous                     {
187daf36e2eSEd Tanous                         continue;
188daf36e2eSEd Tanous                     }
1891abe55efSEd Tanous                     if (connectionNames.size() < 1)
1901abe55efSEd Tanous                     {
1911abe55efSEd Tanous                         BMCWEB_LOG_ERROR << "Only got "
1921abe55efSEd Tanous                                          << connectionNames.size()
19355c7b7a2SEd Tanous                                          << " Connection names";
194e0d918bcSEd Tanous                         continue;
195daf36e2eSEd Tanous                     }
196e0d918bcSEd Tanous 
197daf36e2eSEd Tanous                     const std::string connectionName = connectionNames[0].first;
19855c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
19962d5e2e4SEd Tanous                         [asyncResp, chassisId(std::string(chassisId))](
20062d5e2e4SEd Tanous                             const boost::system::error_code ec,
2011abe55efSEd Tanous                             const std::vector<std::pair<
2021abe55efSEd Tanous                                 std::string, VariantType>> &propertiesList) {
2031abe55efSEd Tanous                             for (const std::pair<std::string, VariantType>
2041abe55efSEd Tanous                                      &property : propertiesList)
2051abe55efSEd Tanous                             {
206daf36e2eSEd Tanous                                 const std::string *value =
2071abe55efSEd Tanous                                     mapbox::getPtr<const std::string>(
2081abe55efSEd Tanous                                         property.second);
2091abe55efSEd Tanous                                 if (value != nullptr)
2101abe55efSEd Tanous                                 {
21162d5e2e4SEd Tanous                                     asyncResp->res.jsonValue[property.first] =
21262d5e2e4SEd Tanous                                         *value;
213daf36e2eSEd Tanous                                 }
214daf36e2eSEd Tanous                             }
21562d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Name"] = chassisId;
21662d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Id"] = chassisId;
21762d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Thermal"] = {
2181abe55efSEd Tanous                                 {"@odata.id", "/redfish/v1/Chassis/" +
2191abe55efSEd Tanous                                                   chassisId + "/Thermal"}};
220daf36e2eSEd Tanous                         },
221daf36e2eSEd Tanous                         connectionName, path, "org.freedesktop.DBus.Properties",
2221abe55efSEd Tanous                         "GetAll",
2231abe55efSEd Tanous                         "xyz.openbmc_project.Inventory.Decorator.Asset");
224daf36e2eSEd Tanous                     return;
225daf36e2eSEd Tanous                 }
226e0d918bcSEd Tanous 
227daf36e2eSEd Tanous                 // Couldn't find an object with that name.  return an error
22862d5e2e4SEd Tanous                 asyncResp->res.jsonValue = redfish::messages::resourceNotFound(
22962d5e2e4SEd Tanous                     "#Chassis.v1_4_0.Chassis", chassisId);
23062d5e2e4SEd Tanous                 asyncResp->res.result(boost::beast::http::status::not_found);
231daf36e2eSEd Tanous             },
232daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper",
233daf36e2eSEd Tanous             "/xyz/openbmc_project/object_mapper",
234daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
235daf36e2eSEd Tanous             "/xyz/openbmc_project/inventory", int32_t(0),
236daf36e2eSEd Tanous             std::array<const char *, 1>{
237daf36e2eSEd Tanous                 "xyz.openbmc_project.Inventory.Decorator.Asset"});
238e37f8451SRapkiewicz, Pawel     }
23962d5e2e4SEd Tanous };
240e37f8451SRapkiewicz, Pawel } // namespace redfish
241