xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision c181942f49d754983981f9dc24f0129270ab02eb)
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>
21abf2add6SEd Tanous #include <variant>
22e37f8451SRapkiewicz, Pawel 
231abe55efSEd Tanous namespace redfish
241abe55efSEd Tanous {
25e37f8451SRapkiewicz, Pawel 
26e37f8451SRapkiewicz, Pawel /**
27e37f8451SRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
28e37f8451SRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
29e37f8451SRapkiewicz, Pawel  */
3055c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get
31aa2e59c1SEd Tanous // values, it should be as simple as possible
32aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type
33abf2add6SEd Tanous using VariantType = std::variant<bool, std::string, uint64_t>;
34aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair<
35aa2e59c1SEd Tanous     sdbusplus::message::object_path,
36aa2e59c1SEd Tanous     std::vector<std::pair<std::string,
37aa2e59c1SEd Tanous                           std::vector<std::pair<std::string, VariantType>>>>>>;
38e37f8451SRapkiewicz, Pawel 
39aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>;
40e37f8451SRapkiewicz, Pawel 
41*c181942fSQiang XU void getIntrusionByService(std::shared_ptr<AsyncResp> aResp,
42*c181942fSQiang XU                            const std::string &service,
43*c181942fSQiang XU                            const std::string &objPath)
44*c181942fSQiang XU {
45*c181942fSQiang XU     BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
46*c181942fSQiang XU 
47*c181942fSQiang XU     crow::connections::systemBus->async_method_call(
48*c181942fSQiang XU         [aResp{std::move(aResp)}](const boost::system::error_code ec,
49*c181942fSQiang XU                                   const std::variant<std::string> &value) {
50*c181942fSQiang XU             if (ec)
51*c181942fSQiang XU             {
52*c181942fSQiang XU                 // do not add err msg in redfish response, becaues this is not
53*c181942fSQiang XU                 //     mandatory property
54*c181942fSQiang XU                 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
55*c181942fSQiang XU                 return;
56*c181942fSQiang XU             }
57*c181942fSQiang XU 
58*c181942fSQiang XU             const std::string *status = std::get_if<std::string>(&value);
59*c181942fSQiang XU 
60*c181942fSQiang XU             if (status == nullptr)
61*c181942fSQiang XU             {
62*c181942fSQiang XU                 BMCWEB_LOG_ERROR << "intrusion status read error \n";
63*c181942fSQiang XU                 return;
64*c181942fSQiang XU             }
65*c181942fSQiang XU 
66*c181942fSQiang XU             aResp->res.jsonValue["PhysicalSecurity"] = {
67*c181942fSQiang XU                 {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}};
68*c181942fSQiang XU         },
69*c181942fSQiang XU         service, objPath, "org.freedesktop.DBus.Properties", "Get",
70*c181942fSQiang XU         "xyz.openbmc_project.Chassis.Intrusion", "Status");
71*c181942fSQiang XU }
72*c181942fSQiang XU 
73*c181942fSQiang XU /**
74*c181942fSQiang XU  * Retrieves physical security properties over dbus
75*c181942fSQiang XU  */
76*c181942fSQiang XU void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp)
77*c181942fSQiang XU {
78*c181942fSQiang XU     crow::connections::systemBus->async_method_call(
79*c181942fSQiang XU         [aResp{std::move(aResp)}](
80*c181942fSQiang XU             const boost::system::error_code ec,
81*c181942fSQiang XU             const std::vector<std::pair<
82*c181942fSQiang XU                 std::string,
83*c181942fSQiang XU                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
84*c181942fSQiang XU                 &subtree) {
85*c181942fSQiang XU             if (ec)
86*c181942fSQiang XU             {
87*c181942fSQiang XU                 // do not add err msg in redfish response, becaues this is not
88*c181942fSQiang XU                 //     mandatory property
89*c181942fSQiang XU                 BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec
90*c181942fSQiang XU                                  << "\n";
91*c181942fSQiang XU                 return;
92*c181942fSQiang XU             }
93*c181942fSQiang XU             // Iterate over all retrieved ObjectPaths.
94*c181942fSQiang XU             for (const auto &object : subtree)
95*c181942fSQiang XU             {
96*c181942fSQiang XU                 for (const auto &service : object.second)
97*c181942fSQiang XU                 {
98*c181942fSQiang XU                     getIntrusionByService(aResp, service.first, object.first);
99*c181942fSQiang XU                     return;
100*c181942fSQiang XU                 }
101*c181942fSQiang XU             }
102*c181942fSQiang XU         },
103*c181942fSQiang XU         "xyz.openbmc_project.ObjectMapper",
104*c181942fSQiang XU         "/xyz/openbmc_project/object_mapper",
105*c181942fSQiang XU         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
106*c181942fSQiang XU         "/xyz/openbmc_project/Intrusion", int32_t(1),
107*c181942fSQiang XU         std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
108*c181942fSQiang XU }
109*c181942fSQiang XU 
110e37f8451SRapkiewicz, Pawel /**
111e37f8451SRapkiewicz, Pawel  * ChassisCollection derived class for delivering Chassis Collection Schema
112e37f8451SRapkiewicz, Pawel  */
1131abe55efSEd Tanous class ChassisCollection : public Node
1141abe55efSEd Tanous {
115e37f8451SRapkiewicz, Pawel   public:
1161abe55efSEd Tanous     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
1171abe55efSEd Tanous     {
118e0d918bcSEd Tanous         entityPrivileges = {
119e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
120e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
121e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
122e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
123e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
124e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
125e37f8451SRapkiewicz, Pawel     }
126e37f8451SRapkiewicz, Pawel 
127e37f8451SRapkiewicz, Pawel   private:
128e37f8451SRapkiewicz, Pawel     /**
129e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
130e37f8451SRapkiewicz, Pawel      */
13155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1321abe55efSEd Tanous                const std::vector<std::string> &params) override
1331abe55efSEd Tanous     {
1348f1ac8e9SGunnar Mills         const std::array<const char *, 3> interfaces = {
13562d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.Board",
13662d5e2e4SEd Tanous             "xyz.openbmc_project.Inventory.Item.Chassis",
1378f1ac8e9SGunnar Mills             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
1380f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
1390f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
1400f74e643SEd Tanous         res.jsonValue["@odata.context"] =
1410f74e643SEd Tanous             "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
1420f74e643SEd Tanous         res.jsonValue["Name"] = "Chassis Collection";
1430f74e643SEd Tanous 
14462d5e2e4SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
14562d5e2e4SEd Tanous         crow::connections::systemBus->async_method_call(
14662d5e2e4SEd Tanous             [asyncResp](const boost::system::error_code ec,
14762d5e2e4SEd Tanous                         const std::vector<std::string> &chassisList) {
14862d5e2e4SEd Tanous                 if (ec)
1491abe55efSEd Tanous                 {
150f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
15162d5e2e4SEd Tanous                     return;
152e37f8451SRapkiewicz, Pawel                 }
15362d5e2e4SEd Tanous                 nlohmann::json &chassisArray =
15462d5e2e4SEd Tanous                     asyncResp->res.jsonValue["Members"];
15562d5e2e4SEd Tanous                 chassisArray = nlohmann::json::array();
15662d5e2e4SEd Tanous                 for (const std::string &objpath : chassisList)
15762d5e2e4SEd Tanous                 {
15862d5e2e4SEd Tanous                     std::size_t lastPos = objpath.rfind("/");
15962d5e2e4SEd Tanous                     if (lastPos == std::string::npos)
16062d5e2e4SEd Tanous                     {
16162d5e2e4SEd Tanous                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
16262d5e2e4SEd Tanous                         continue;
16362d5e2e4SEd Tanous                     }
16462d5e2e4SEd Tanous                     chassisArray.push_back(
16562d5e2e4SEd Tanous                         {{"@odata.id", "/redfish/v1/Chassis/" +
16662d5e2e4SEd Tanous                                            objpath.substr(lastPos + 1)}});
167e37f8451SRapkiewicz, Pawel                 }
168e37f8451SRapkiewicz, Pawel 
16962d5e2e4SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
17062d5e2e4SEd Tanous                     chassisArray.size();
17162d5e2e4SEd Tanous             },
17262d5e2e4SEd Tanous             "xyz.openbmc_project.ObjectMapper",
17362d5e2e4SEd Tanous             "/xyz/openbmc_project/object_mapper",
17462d5e2e4SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
175734bfe90SGunnar Mills             "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
17662d5e2e4SEd Tanous     }
177e37f8451SRapkiewicz, Pawel };
178e37f8451SRapkiewicz, Pawel 
179e37f8451SRapkiewicz, Pawel /**
180e37f8451SRapkiewicz, Pawel  * Chassis override class for delivering Chassis Schema
181e37f8451SRapkiewicz, Pawel  */
1821abe55efSEd Tanous class Chassis : public Node
1831abe55efSEd Tanous {
184e37f8451SRapkiewicz, Pawel   public:
1851abe55efSEd Tanous     Chassis(CrowApp &app) :
1861abe55efSEd Tanous         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
1871abe55efSEd Tanous     {
188e0d918bcSEd Tanous         entityPrivileges = {
189e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
190e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
191e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
192e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
193e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
194e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
195e37f8451SRapkiewicz, Pawel     }
196e37f8451SRapkiewicz, Pawel 
197e37f8451SRapkiewicz, Pawel   private:
198e37f8451SRapkiewicz, Pawel     /**
199e37f8451SRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
200e37f8451SRapkiewicz, Pawel      */
20155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
2021abe55efSEd Tanous                const std::vector<std::string> &params) override
2031abe55efSEd Tanous     {
204734bfe90SGunnar Mills         const std::array<const char *, 3> interfaces = {
205734bfe90SGunnar Mills             "xyz.openbmc_project.Inventory.Item.Board",
206734bfe90SGunnar Mills             "xyz.openbmc_project.Inventory.Item.Chassis",
207734bfe90SGunnar Mills             "xyz.openbmc_project.Inventory.Item.PowerSupply"};
208734bfe90SGunnar Mills 
209e37f8451SRapkiewicz, Pawel         // Check if there is required param, truly entering this shall be
210e37f8451SRapkiewicz, Pawel         // impossible.
2111abe55efSEd Tanous         if (params.size() != 1)
2121abe55efSEd Tanous         {
213f12894f8SJason M. Bills             messages::internalError(res);
214e37f8451SRapkiewicz, Pawel             res.end();
215e37f8451SRapkiewicz, Pawel             return;
216e37f8451SRapkiewicz, Pawel         }
21799cffd7fSShawn McCarney         const std::string &chassisId = params[0];
218e37f8451SRapkiewicz, Pawel 
2190f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
22099cffd7fSShawn McCarney         res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + chassisId;
2210f74e643SEd Tanous         res.jsonValue["@odata.context"] =
2220f74e643SEd Tanous             "/redfish/v1/$metadata#Chassis.Chassis";
2230f74e643SEd Tanous         res.jsonValue["Name"] = "Chassis Collection";
2240f74e643SEd Tanous         res.jsonValue["ChassisType"] = "RackMount";
2250f74e643SEd Tanous         res.jsonValue["PowerState"] = "On";
2260f74e643SEd Tanous 
22762d5e2e4SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
22855c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
22962d5e2e4SEd Tanous             [asyncResp, chassisId(std::string(chassisId))](
23062d5e2e4SEd Tanous                 const boost::system::error_code ec,
231daf36e2eSEd Tanous                 const std::vector<std::pair<
2321abe55efSEd Tanous                     std::string, std::vector<std::pair<
2331abe55efSEd Tanous                                      std::string, std::vector<std::string>>>>>
234daf36e2eSEd Tanous                     &subtree) {
23562d5e2e4SEd Tanous                 if (ec)
2361abe55efSEd Tanous                 {
237f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
238daf36e2eSEd Tanous                     return;
239daf36e2eSEd Tanous                 }
240daf36e2eSEd Tanous                 // Iterate over all retrieved ObjectPaths.
2411abe55efSEd Tanous                 for (const std::pair<
2421abe55efSEd Tanous                          std::string,
2431abe55efSEd Tanous                          std::vector<
2441abe55efSEd Tanous                              std::pair<std::string, std::vector<std::string>>>>
2451abe55efSEd Tanous                          &object : subtree)
2461abe55efSEd Tanous                 {
247daf36e2eSEd Tanous                     const std::string &path = object.first;
2481abe55efSEd Tanous                     const std::vector<
2491abe55efSEd Tanous                         std::pair<std::string, std::vector<std::string>>>
250daf36e2eSEd Tanous                         &connectionNames = object.second;
251e0d918bcSEd Tanous 
2521abe55efSEd Tanous                     if (!boost::ends_with(path, chassisId))
2531abe55efSEd Tanous                     {
254daf36e2eSEd Tanous                         continue;
255daf36e2eSEd Tanous                     }
2561abe55efSEd Tanous                     if (connectionNames.size() < 1)
2571abe55efSEd Tanous                     {
2581abe55efSEd Tanous                         BMCWEB_LOG_ERROR << "Only got "
2591abe55efSEd Tanous                                          << connectionNames.size()
26055c7b7a2SEd Tanous                                          << " Connection names";
261e0d918bcSEd Tanous                         continue;
262daf36e2eSEd Tanous                     }
263e0d918bcSEd Tanous 
264daf36e2eSEd Tanous                     const std::string connectionName = connectionNames[0].first;
26555c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
26662d5e2e4SEd Tanous                         [asyncResp, chassisId(std::string(chassisId))](
26762d5e2e4SEd Tanous                             const boost::system::error_code ec,
2681abe55efSEd Tanous                             const std::vector<std::pair<
2691abe55efSEd Tanous                                 std::string, VariantType>> &propertiesList) {
2701abe55efSEd Tanous                             for (const std::pair<std::string, VariantType>
2711abe55efSEd Tanous                                      &property : propertiesList)
2721abe55efSEd Tanous                             {
27399cffd7fSShawn McCarney                                 // Store DBus properties that are also Redfish
27499cffd7fSShawn McCarney                                 // properties with same name and a string value
27599cffd7fSShawn McCarney                                 const std::string &propertyName =
27699cffd7fSShawn McCarney                                     property.first;
27799cffd7fSShawn McCarney                                 if ((propertyName == "PartNumber") ||
27899cffd7fSShawn McCarney                                     (propertyName == "SerialNumber") ||
27999cffd7fSShawn McCarney                                     (propertyName == "Manufacturer") ||
28099cffd7fSShawn McCarney                                     (propertyName == "Model"))
28199cffd7fSShawn McCarney                                 {
282daf36e2eSEd Tanous                                     const std::string *value =
28399cffd7fSShawn McCarney                                         std::get_if<std::string>(
28499cffd7fSShawn McCarney                                             &property.second);
2851abe55efSEd Tanous                                     if (value != nullptr)
2861abe55efSEd Tanous                                     {
28799cffd7fSShawn McCarney                                         asyncResp->res.jsonValue[propertyName] =
28862d5e2e4SEd Tanous                                             *value;
289daf36e2eSEd Tanous                                     }
290daf36e2eSEd Tanous                                 }
29199cffd7fSShawn McCarney                             }
29262d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Name"] = chassisId;
29362d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Id"] = chassisId;
29462d5e2e4SEd Tanous                             asyncResp->res.jsonValue["Thermal"] = {
2951abe55efSEd Tanous                                 {"@odata.id", "/redfish/v1/Chassis/" +
2961abe55efSEd Tanous                                                   chassisId + "/Thermal"}};
2972474adfaSEd Tanous                             // Power object
2982474adfaSEd Tanous                             asyncResp->res.jsonValue["Power"] = {
2992474adfaSEd Tanous                                 {"@odata.id", "/redfish/v1/Chassis/" +
3002474adfaSEd Tanous                                                   chassisId + "/Power"}};
301029573d4SEd Tanous                             asyncResp->res.jsonValue["Status"] = {
302029573d4SEd Tanous                                 {"Health", "OK"},
303029573d4SEd Tanous                                 {"State", "Enabled"},
304029573d4SEd Tanous                             };
3052474adfaSEd Tanous 
306029573d4SEd Tanous                             asyncResp->res
307029573d4SEd Tanous                                 .jsonValue["Links"]["ComputerSystems"] = {
308029573d4SEd Tanous                                 {{"@odata.id", "/redfish/v1/Systems/system"}}};
309029573d4SEd Tanous                             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
310029573d4SEd Tanous                                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
311daf36e2eSEd Tanous                         },
312daf36e2eSEd Tanous                         connectionName, path, "org.freedesktop.DBus.Properties",
3131abe55efSEd Tanous                         "GetAll",
3141abe55efSEd Tanous                         "xyz.openbmc_project.Inventory.Decorator.Asset");
315daf36e2eSEd Tanous                     return;
316daf36e2eSEd Tanous                 }
317e0d918bcSEd Tanous 
318daf36e2eSEd Tanous                 // Couldn't find an object with that name.  return an error
319f12894f8SJason M. Bills                 messages::resourceNotFound(
320f12894f8SJason M. Bills                     asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
321daf36e2eSEd Tanous             },
322daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper",
323daf36e2eSEd Tanous             "/xyz/openbmc_project/object_mapper",
324daf36e2eSEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
325734bfe90SGunnar Mills             "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
326*c181942fSQiang XU 
327*c181942fSQiang XU         getPhysicalSecurityData(asyncResp);
328e37f8451SRapkiewicz, Pawel     }
32962d5e2e4SEd Tanous };
330e37f8451SRapkiewicz, Pawel } // namespace redfish
331