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