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