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 <sdbusplus/asio/property.hpp> 12 #include <sdbusplus/unpack_properties.hpp> 13 14 #include <array> 15 #include <string_view> 16 17 namespace redfish 18 { 19 /** 20 * @brief Fill cable specific properties. 21 * @param[in,out] resp HTTP response. 22 * @param[in] ec Error code corresponding to Async method call. 23 * @param[in] properties List of Cable Properties key/value pairs. 24 */ 25 inline void 26 fillCableProperties(crow::Response& resp, 27 const boost::system::error_code& ec, 28 const dbus::utility::DBusPropertiesMap& properties) 29 { 30 if (ec) 31 { 32 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 33 messages::internalError(resp); 34 return; 35 } 36 37 const std::string* cableTypeDescription = nullptr; 38 const double* length = nullptr; 39 40 const bool success = sdbusplus::unpackPropertiesNoThrow( 41 dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription", 42 cableTypeDescription, "Length", length); 43 44 if (!success) 45 { 46 messages::internalError(resp); 47 return; 48 } 49 50 if (cableTypeDescription != nullptr) 51 { 52 resp.jsonValue["CableType"] = *cableTypeDescription; 53 } 54 55 if (length != nullptr) 56 { 57 if (!std::isfinite(*length)) 58 { 59 // Cable length is NaN by default, do not throw an error 60 if (!std::isnan(*length)) 61 { 62 messages::internalError(resp); 63 return; 64 } 65 } 66 else 67 { 68 resp.jsonValue["LengthMeters"] = *length; 69 } 70 } 71 } 72 73 /** 74 * @brief Api to get Cable properties. 75 * @param[in,out] asyncResp Async HTTP response. 76 * @param[in] cableObjectPath Object path of the Cable. 77 * @param[in] serviceMap A map to hold Service and corresponding 78 * interface list for the given cable id. 79 */ 80 inline void 81 getCableProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 82 const std::string& cableObjectPath, 83 const dbus::utility::MapperServiceMap& serviceMap) 84 { 85 BMCWEB_LOG_DEBUG << "Get Properties for cable " << cableObjectPath; 86 87 for (const auto& [service, interfaces] : serviceMap) 88 { 89 for (const auto& interface : interfaces) 90 { 91 if (interface != "xyz.openbmc_project.Inventory.Item.Cable") 92 { 93 continue; 94 } 95 96 sdbusplus::asio::getAllProperties( 97 *crow::connections::systemBus, service, cableObjectPath, 98 interface, 99 [asyncResp]( 100 const boost::system::error_code& ec, 101 const dbus::utility::DBusPropertiesMap& properties) { 102 fillCableProperties(asyncResp->res, ec, properties); 103 }); 104 } 105 } 106 } 107 108 /** 109 * The Cable schema 110 */ 111 inline void requestRoutesCable(App& app) 112 { 113 BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/") 114 .privileges(redfish::privileges::getCable) 115 .methods(boost::beast::http::verb::get)( 116 [&app](const crow::Request& req, 117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 118 const std::string& cableId) { 119 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 120 { 121 return; 122 } 123 BMCWEB_LOG_DEBUG << "Cable Id: " << cableId; 124 constexpr std::array<std::string_view, 1> interfaces = { 125 "xyz.openbmc_project.Inventory.Item.Cable"}; 126 dbus::utility::getSubTree( 127 "/xyz/openbmc_project/inventory", 0, interfaces, 128 [asyncResp, 129 cableId](const boost::system::error_code& ec, 130 const dbus::utility::MapperGetSubTreeResponse& subtree) { 131 if (ec.value() == EBADR) 132 { 133 messages::resourceNotFound(asyncResp->res, "Cable", cableId); 134 return; 135 } 136 137 if (ec) 138 { 139 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 140 messages::internalError(asyncResp->res); 141 return; 142 } 143 144 for (const auto& [objectPath, serviceMap] : subtree) 145 { 146 sdbusplus::message::object_path path(objectPath); 147 if (path.filename() != cableId) 148 { 149 continue; 150 } 151 152 asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable"; 153 asyncResp->res.jsonValue["@odata.id"] = 154 crow::utility::urlFromPieces("redfish", "v1", "Cables", 155 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