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 */
fillCableProperties(crow::Response & resp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)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
getCableProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & cableObjectPath,const dbus::utility::MapperServiceMap & serviceMap)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 */
requestRoutesCable(App & app)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 */
requestRoutesCableCollection(App & app)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