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