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