1 #pragma once 2 3 #include "dbus_utility.hpp" 4 5 #include <query.hpp> 6 #include <sdbusplus/asio/property.hpp> 7 #include <sdbusplus/unpack_properties.hpp> 8 #include <utils/dbus_utils.hpp> 9 #include <utils/json_utils.hpp> 10 11 #include <array> 12 #include <string_view> 13 14 namespace redfish 15 { 16 /** 17 * @brief Fill cable specific properties. 18 * @param[in,out] resp HTTP response. 19 * @param[in] ec Error code corresponding to Async method call. 20 * @param[in] properties List of Cable Properties key/value pairs. 21 */ 22 inline void 23 fillCableProperties(crow::Response& resp, 24 const boost::system::error_code ec, 25 const dbus::utility::DBusPropertiesMap& properties) 26 { 27 if (ec) 28 { 29 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 30 messages::internalError(resp); 31 return; 32 } 33 34 const std::string* cableTypeDescription = nullptr; 35 const double* length = nullptr; 36 37 const bool success = sdbusplus::unpackPropertiesNoThrow( 38 dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription", 39 cableTypeDescription, "Length", length); 40 41 if (!success) 42 { 43 messages::internalError(resp); 44 return; 45 } 46 47 if (cableTypeDescription != nullptr) 48 { 49 resp.jsonValue["CableType"] = *cableTypeDescription; 50 } 51 52 if (length != nullptr) 53 { 54 if (!std::isfinite(*length)) 55 { 56 // Cable length is NaN by default, do not throw an error 57 if (!std::isnan(*length)) 58 { 59 messages::internalError(resp); 60 return; 61 } 62 } 63 else 64 { 65 resp.jsonValue["LengthMeters"] = *length; 66 } 67 } 68 } 69 70 /** 71 * @brief Api to get Cable properties. 72 * @param[in,out] asyncResp Async HTTP response. 73 * @param[in] cableObjectPath Object path of the Cable. 74 * @param[in] serviceMap A map to hold Service and corresponding 75 * interface list for the given cable id. 76 */ 77 inline void 78 getCableProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 79 const std::string& cableObjectPath, 80 const dbus::utility::MapperServiceMap& serviceMap) 81 { 82 BMCWEB_LOG_DEBUG << "Get Properties for cable " << cableObjectPath; 83 84 for (const auto& [service, interfaces] : serviceMap) 85 { 86 for (const auto& interface : interfaces) 87 { 88 if (interface != "xyz.openbmc_project.Inventory.Item.Cable") 89 { 90 continue; 91 } 92 93 sdbusplus::asio::getAllProperties( 94 *crow::connections::systemBus, service, cableObjectPath, 95 interface, 96 [asyncResp]( 97 const boost::system::error_code ec, 98 const dbus::utility::DBusPropertiesMap& properties) { 99 fillCableProperties(asyncResp->res, ec, properties); 100 }); 101 } 102 } 103 } 104 105 /** 106 * The Cable schema 107 */ 108 inline void requestRoutesCable(App& app) 109 { 110 BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/") 111 .privileges(redfish::privileges::getCable) 112 .methods(boost::beast::http::verb::get)( 113 [&app](const crow::Request& req, 114 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 115 const std::string& cableId) { 116 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117 { 118 return; 119 } 120 BMCWEB_LOG_DEBUG << "Cable Id: " << cableId; 121 auto respHandler = 122 [asyncResp, 123 cableId](const boost::system::error_code ec, 124 const dbus::utility::MapperGetSubTreeResponse& subtree) { 125 if (ec.value() == EBADR) 126 { 127 messages::resourceNotFound(asyncResp->res, "Cable", cableId); 128 return; 129 } 130 131 if (ec) 132 { 133 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 134 messages::internalError(asyncResp->res); 135 return; 136 } 137 138 for (const auto& [objectPath, serviceMap] : subtree) 139 { 140 sdbusplus::message::object_path path(objectPath); 141 if (path.filename() != cableId) 142 { 143 continue; 144 } 145 146 asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable"; 147 asyncResp->res.jsonValue["@odata.id"] = 148 "/redfish/v1/Cables/" + cableId; 149 asyncResp->res.jsonValue["Id"] = cableId; 150 asyncResp->res.jsonValue["Name"] = "Cable"; 151 152 getCableProperties(asyncResp, objectPath, serviceMap); 153 return; 154 } 155 messages::resourceNotFound(asyncResp->res, "Cable", cableId); 156 }; 157 158 crow::connections::systemBus->async_method_call( 159 respHandler, "xyz.openbmc_project.ObjectMapper", 160 "/xyz/openbmc_project/object_mapper", 161 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 162 "/xyz/openbmc_project/inventory", 0, 163 std::array<const char*, 1>{ 164 "xyz.openbmc_project.Inventory.Item.Cable"}); 165 }); 166 } 167 168 /** 169 * Collection of Cable resource instances 170 */ 171 inline void requestRoutesCableCollection(App& app) 172 { 173 BMCWEB_ROUTE(app, "/redfish/v1/Cables/") 174 .privileges(redfish::privileges::getCableCollection) 175 .methods(boost::beast::http::verb::get)( 176 [&app](const crow::Request& req, 177 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 178 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 179 { 180 return; 181 } 182 asyncResp->res.jsonValue["@odata.type"] = 183 "#CableCollection.CableCollection"; 184 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables"; 185 asyncResp->res.jsonValue["Name"] = "Cable Collection"; 186 asyncResp->res.jsonValue["Description"] = "Collection of Cable Entries"; 187 constexpr std::array<std::string_view, 1> interfaces{ 188 "xyz.openbmc_project.Inventory.Item.Cable"}; 189 collection_util::getCollectionMembers( 190 asyncResp, boost::urls::url("/redfish/v1/Cables"), interfaces); 191 }); 192 } 193 194 } // namespace redfish 195