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 fillCableProperties( 28 crow::Response& resp, const boost::system::error_code& ec, 29 const dbus::utility::DBusPropertiesMap& properties) 30 { 31 if (ec) 32 { 33 BMCWEB_LOG_ERROR("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 sdbusplus::asio::getAllProperties( 95 *crow::connections::systemBus, service, cableObjectPath, 96 interface, 97 [asyncResp]( 98 const boost::system::error_code& ec, 99 const dbus::utility::DBusPropertiesMap& properties) { 100 fillCableProperties(asyncResp->res, ec, properties); 101 }); 102 } 103 else if (interface == "xyz.openbmc_project.Inventory.Item") 104 { 105 sdbusplus::asio::getProperty<bool>( 106 *crow::connections::systemBus, service, cableObjectPath, 107 interface, "Present", 108 [asyncResp, cableObjectPath]( 109 const boost::system::error_code& ec, bool present) { 110 if (ec) 111 { 112 BMCWEB_LOG_DEBUG( 113 "get presence failed for Cable {} with error {}", 114 cableObjectPath, ec); 115 if (ec.value() != EBADR) 116 { 117 messages::internalError(asyncResp->res); 118 } 119 return; 120 } 121 122 if (!present) 123 { 124 asyncResp->res.jsonValue["Status"]["State"] = 125 resource::State::Absent; 126 } 127 }); 128 } 129 } 130 } 131 } 132 133 /** 134 * The Cable schema 135 */ 136 inline void requestRoutesCable(App& app) 137 { 138 BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/") 139 .privileges(redfish::privileges::getCable) 140 .methods(boost::beast::http::verb::get)( 141 [&app](const crow::Request& req, 142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 143 const std::string& cableId) { 144 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 145 { 146 return; 147 } 148 BMCWEB_LOG_DEBUG("Cable Id: {}", cableId); 149 constexpr std::array<std::string_view, 1> interfaces = { 150 "xyz.openbmc_project.Inventory.Item.Cable"}; 151 dbus::utility::getSubTree( 152 "/xyz/openbmc_project/inventory", 0, interfaces, 153 [asyncResp, 154 cableId](const boost::system::error_code& ec, 155 const dbus::utility::MapperGetSubTreeResponse& 156 subtree) { 157 if (ec.value() == EBADR) 158 { 159 messages::resourceNotFound(asyncResp->res, "Cable", 160 cableId); 161 return; 162 } 163 164 if (ec) 165 { 166 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 167 messages::internalError(asyncResp->res); 168 return; 169 } 170 171 for (const auto& [objectPath, serviceMap] : subtree) 172 { 173 sdbusplus::message::object_path path(objectPath); 174 if (path.filename() != cableId) 175 { 176 continue; 177 } 178 179 asyncResp->res.jsonValue["@odata.type"] = 180 "#Cable.v1_0_0.Cable"; 181 asyncResp->res.jsonValue["@odata.id"] = 182 boost::urls::format("/redfish/v1/Cables/{}", 183 cableId); 184 asyncResp->res.jsonValue["Id"] = cableId; 185 asyncResp->res.jsonValue["Name"] = "Cable"; 186 asyncResp->res.jsonValue["Status"]["State"] = 187 resource::State::Enabled; 188 189 getCableProperties(asyncResp, objectPath, 190 serviceMap); 191 return; 192 } 193 messages::resourceNotFound(asyncResp->res, "Cable", 194 cableId); 195 }); 196 }); 197 } 198 199 /** 200 * Collection of Cable resource instances 201 */ 202 inline void requestRoutesCableCollection(App& app) 203 { 204 BMCWEB_ROUTE(app, "/redfish/v1/Cables/") 205 .privileges(redfish::privileges::getCableCollection) 206 .methods(boost::beast::http::verb::get)( 207 [&app](const crow::Request& req, 208 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 209 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 210 { 211 return; 212 } 213 asyncResp->res.jsonValue["@odata.type"] = 214 "#CableCollection.CableCollection"; 215 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables"; 216 asyncResp->res.jsonValue["Name"] = "Cable Collection"; 217 asyncResp->res.jsonValue["Description"] = 218 "Collection of Cable Entries"; 219 constexpr std::array<std::string_view, 1> interfaces{ 220 "xyz.openbmc_project.Inventory.Item.Cable"}; 221 collection_util::getCollectionMembers( 222 asyncResp, boost::urls::url("/redfish/v1/Cables"), 223 interfaces, "/xyz/openbmc_project/inventory"); 224 }); 225 } 226 227 } // namespace redfish 228