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