xref: /openbmc/bmcweb/redfish-core/lib/cable.hpp (revision 7a1dbc48)
1 #pragma once
2 
3 #include "dbus_utility.hpp"
4 
5 #include <query.hpp>
6 #include <sdbusplus/asio/property.hpp>
7 #include <sdbusplus/unpack_properties.hpp>
8 #include <utils/dbus_utils.hpp>
9 #include <utils/json_utils.hpp>
10 
11 #include <array>
12 #include <string_view>
13 
14 namespace redfish
15 {
16 /**
17  * @brief Fill cable specific properties.
18  * @param[in,out]   resp        HTTP response.
19  * @param[in]       ec          Error code corresponding to Async method call.
20  * @param[in]       properties  List of Cable Properties key/value pairs.
21  */
22 inline void
23     fillCableProperties(crow::Response& resp,
24                         const boost::system::error_code ec,
25                         const dbus::utility::DBusPropertiesMap& properties)
26 {
27     if (ec)
28     {
29         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
30         messages::internalError(resp);
31         return;
32     }
33 
34     const std::string* cableTypeDescription = nullptr;
35     const double* length = nullptr;
36 
37     const bool success = sdbusplus::unpackPropertiesNoThrow(
38         dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription",
39         cableTypeDescription, "Length", length);
40 
41     if (!success)
42     {
43         messages::internalError(resp);
44         return;
45     }
46 
47     if (cableTypeDescription != nullptr)
48     {
49         resp.jsonValue["CableType"] = *cableTypeDescription;
50     }
51 
52     if (length != nullptr)
53     {
54         if (!std::isfinite(*length))
55         {
56             // Cable length is NaN by default, do not throw an error
57             if (!std::isnan(*length))
58             {
59                 messages::internalError(resp);
60                 return;
61             }
62         }
63         else
64         {
65             resp.jsonValue["LengthMeters"] = *length;
66         }
67     }
68 }
69 
70 /**
71  * @brief Api to get Cable properties.
72  * @param[in,out]   asyncResp       Async HTTP response.
73  * @param[in]       cableObjectPath Object path of the Cable.
74  * @param[in]       serviceMap      A map to hold Service and corresponding
75  * interface list for the given cable id.
76  */
77 inline void
78     getCableProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
79                        const std::string& cableObjectPath,
80                        const dbus::utility::MapperServiceMap& serviceMap)
81 {
82     BMCWEB_LOG_DEBUG << "Get Properties for cable " << cableObjectPath;
83 
84     for (const auto& [service, interfaces] : serviceMap)
85     {
86         for (const auto& interface : interfaces)
87         {
88             if (interface != "xyz.openbmc_project.Inventory.Item.Cable")
89             {
90                 continue;
91             }
92 
93             sdbusplus::asio::getAllProperties(
94                 *crow::connections::systemBus, service, cableObjectPath,
95                 interface,
96                 [asyncResp](
97                     const boost::system::error_code ec,
98                     const dbus::utility::DBusPropertiesMap& properties) {
99                 fillCableProperties(asyncResp->res, ec, properties);
100                 });
101         }
102     }
103 }
104 
105 /**
106  * The Cable schema
107  */
108 inline void requestRoutesCable(App& app)
109 {
110     BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/")
111         .privileges(redfish::privileges::getCable)
112         .methods(boost::beast::http::verb::get)(
113             [&app](const crow::Request& req,
114                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
115                    const std::string& cableId) {
116         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
117         {
118             return;
119         }
120         BMCWEB_LOG_DEBUG << "Cable Id: " << cableId;
121         auto respHandler =
122             [asyncResp,
123              cableId](const boost::system::error_code ec,
124                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
125             if (ec.value() == EBADR)
126             {
127                 messages::resourceNotFound(asyncResp->res, "Cable", cableId);
128                 return;
129             }
130 
131             if (ec)
132             {
133                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
134                 messages::internalError(asyncResp->res);
135                 return;
136             }
137 
138             for (const auto& [objectPath, serviceMap] : subtree)
139             {
140                 sdbusplus::message::object_path path(objectPath);
141                 if (path.filename() != cableId)
142                 {
143                     continue;
144                 }
145 
146                 asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable";
147                 asyncResp->res.jsonValue["@odata.id"] =
148                     "/redfish/v1/Cables/" + cableId;
149                 asyncResp->res.jsonValue["Id"] = cableId;
150                 asyncResp->res.jsonValue["Name"] = "Cable";
151 
152                 getCableProperties(asyncResp, objectPath, serviceMap);
153                 return;
154             }
155             messages::resourceNotFound(asyncResp->res, "Cable", cableId);
156         };
157 
158         crow::connections::systemBus->async_method_call(
159             respHandler, "xyz.openbmc_project.ObjectMapper",
160             "/xyz/openbmc_project/object_mapper",
161             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
162             "/xyz/openbmc_project/inventory", 0,
163             std::array<const char*, 1>{
164                 "xyz.openbmc_project.Inventory.Item.Cable"});
165         });
166 }
167 
168 /**
169  * Collection of Cable resource instances
170  */
171 inline void requestRoutesCableCollection(App& app)
172 {
173     BMCWEB_ROUTE(app, "/redfish/v1/Cables/")
174         .privileges(redfish::privileges::getCableCollection)
175         .methods(boost::beast::http::verb::get)(
176             [&app](const crow::Request& req,
177                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
178         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
179         {
180             return;
181         }
182         asyncResp->res.jsonValue["@odata.type"] =
183             "#CableCollection.CableCollection";
184         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables";
185         asyncResp->res.jsonValue["Name"] = "Cable Collection";
186         asyncResp->res.jsonValue["Description"] = "Collection of Cable Entries";
187         constexpr std::array<std::string_view, 1> interfaces{
188             "xyz.openbmc_project.Inventory.Item.Cable"};
189         collection_util::getCollectionMembers(
190             asyncResp, boost::urls::url("/redfish/v1/Cables"), interfaces);
191         });
192 }
193 
194 } // namespace redfish
195