xref: /openbmc/bmcweb/redfish-core/lib/cable.hpp (revision f263e09c)
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 <boost/url/format.hpp>
12 #include <sdbusplus/asio/property.hpp>
13 #include <sdbusplus/unpack_properties.hpp>
14 
15 #include <array>
16 #include <string_view>
17 
18 namespace redfish
19 {
20 /**
21  * @brief Fill cable specific properties.
22  * @param[in,out]   resp        HTTP response.
23  * @param[in]       ec          Error code corresponding to Async method call.
24  * @param[in]       properties  List of Cable Properties key/value pairs.
25  */
26 inline void
27     fillCableProperties(crow::Response& resp,
28                         const boost::system::error_code& ec,
29                         const dbus::utility::DBusPropertiesMap& properties)
30 {
31     if (ec)
32     {
33         BMCWEB_LOG_DEBUG << "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                 continue;
95             }
96 
97             sdbusplus::asio::getAllProperties(
98                 *crow::connections::systemBus, service, cableObjectPath,
99                 interface,
100                 [asyncResp](
101                     const boost::system::error_code& ec,
102                     const dbus::utility::DBusPropertiesMap& properties) {
103                 fillCableProperties(asyncResp->res, ec, properties);
104                 });
105         }
106     }
107 }
108 
109 /**
110  * The Cable schema
111  */
112 inline void requestRoutesCable(App& app)
113 {
114     BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/")
115         .privileges(redfish::privileges::getCable)
116         .methods(boost::beast::http::verb::get)(
117             [&app](const crow::Request& req,
118                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
119                    const std::string& cableId) {
120         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121         {
122             return;
123         }
124         BMCWEB_LOG_DEBUG << "Cable Id: " << cableId;
125         constexpr std::array<std::string_view, 1> interfaces = {
126             "xyz.openbmc_project.Inventory.Item.Cable"};
127         dbus::utility::getSubTree(
128             "/xyz/openbmc_project/inventory", 0, interfaces,
129             [asyncResp,
130              cableId](const boost::system::error_code& ec,
131                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
132             if (ec.value() == EBADR)
133             {
134                 messages::resourceNotFound(asyncResp->res, "Cable", cableId);
135                 return;
136             }
137 
138             if (ec)
139             {
140                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
141                 messages::internalError(asyncResp->res);
142                 return;
143             }
144 
145             for (const auto& [objectPath, serviceMap] : subtree)
146             {
147                 sdbusplus::message::object_path path(objectPath);
148                 if (path.filename() != cableId)
149                 {
150                     continue;
151                 }
152 
153                 asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable";
154                 asyncResp->res.jsonValue["@odata.id"] =
155                     boost::urls::format("/redfish/v1/Cables/{}", cableId);
156                 asyncResp->res.jsonValue["Id"] = cableId;
157                 asyncResp->res.jsonValue["Name"] = "Cable";
158 
159                 getCableProperties(asyncResp, objectPath, serviceMap);
160                 return;
161             }
162             messages::resourceNotFound(asyncResp->res, "Cable", cableId);
163             });
164         });
165 }
166 
167 /**
168  * Collection of Cable resource instances
169  */
170 inline void requestRoutesCableCollection(App& app)
171 {
172     BMCWEB_ROUTE(app, "/redfish/v1/Cables/")
173         .privileges(redfish::privileges::getCableCollection)
174         .methods(boost::beast::http::verb::get)(
175             [&app](const crow::Request& req,
176                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
177         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
178         {
179             return;
180         }
181         asyncResp->res.jsonValue["@odata.type"] =
182             "#CableCollection.CableCollection";
183         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables";
184         asyncResp->res.jsonValue["Name"] = "Cable Collection";
185         asyncResp->res.jsonValue["Description"] = "Collection of Cable Entries";
186         constexpr std::array<std::string_view, 1> interfaces{
187             "xyz.openbmc_project.Inventory.Item.Cable"};
188         collection_util::getCollectionMembers(
189             asyncResp, boost::urls::url("/redfish/v1/Cables"), interfaces);
190         });
191 }
192 
193 } // namespace redfish
194