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