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