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