1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #pragma once 4 5 #include "dbus_utility.hpp" 6 #include "generated/enums/resource.hpp" 7 #include "query.hpp" 8 #include "registries/privilege_registry.hpp" 9 #include "utils/collection.hpp" 10 #include "utils/dbus_utils.hpp" 11 #include "utils/json_utils.hpp" 12 13 #include <boost/system/error_code.hpp> 14 #include <boost/url/format.hpp> 15 #include <sdbusplus/asio/property.hpp> 16 #include <sdbusplus/unpack_properties.hpp> 17 18 #include <array> 19 #include <string_view> 20 21 namespace redfish 22 { 23 /** 24 * @brief Fill cable specific properties. 25 * @param[in,out] resp HTTP response. 26 * @param[in] ec Error code corresponding to Async method call. 27 * @param[in] properties List of Cable Properties key/value pairs. 28 */ 29 inline void fillCableProperties( 30 crow::Response& resp, const boost::system::error_code& ec, 31 const dbus::utility::DBusPropertiesMap& properties) 32 { 33 if (ec) 34 { 35 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 36 messages::internalError(resp); 37 return; 38 } 39 40 const std::string* cableTypeDescription = nullptr; 41 const double* length = nullptr; 42 43 const bool success = sdbusplus::unpackPropertiesNoThrow( 44 dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription", 45 cableTypeDescription, "Length", length); 46 47 if (!success) 48 { 49 messages::internalError(resp); 50 return; 51 } 52 53 if (cableTypeDescription != nullptr) 54 { 55 resp.jsonValue["CableType"] = *cableTypeDescription; 56 } 57 58 if (length != nullptr) 59 { 60 if (!std::isfinite(*length)) 61 { 62 // Cable length is NaN by default, do not throw an error 63 if (!std::isnan(*length)) 64 { 65 messages::internalError(resp); 66 return; 67 } 68 } 69 else 70 { 71 resp.jsonValue["LengthMeters"] = *length; 72 } 73 } 74 } 75 76 /** 77 * @brief Api to get Cable properties. 78 * @param[in,out] asyncResp Async HTTP response. 79 * @param[in] cableObjectPath Object path of the Cable. 80 * @param[in] serviceMap A map to hold Service and corresponding 81 * interface list for the given cable id. 82 */ 83 inline void 84 getCableProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 85 const std::string& cableObjectPath, 86 const dbus::utility::MapperServiceMap& serviceMap) 87 { 88 BMCWEB_LOG_DEBUG("Get Properties for cable {}", cableObjectPath); 89 90 for (const auto& [service, interfaces] : serviceMap) 91 { 92 for (const auto& interface : interfaces) 93 { 94 if (interface == "xyz.openbmc_project.Inventory.Item.Cable") 95 { 96 dbus::utility::getAllProperties( 97 *crow::connections::systemBus, service, cableObjectPath, 98 interface, 99 [asyncResp]( 100 const boost::system::error_code& ec, 101 const dbus::utility::DBusPropertiesMap& properties) { 102 fillCableProperties(asyncResp->res, ec, properties); 103 }); 104 } 105 else if (interface == "xyz.openbmc_project.Inventory.Item") 106 { 107 dbus::utility::getProperty<bool>( 108 service, cableObjectPath, 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& 157 subtree) { 158 if (ec.value() == EBADR) 159 { 160 messages::resourceNotFound(asyncResp->res, "Cable", 161 cableId); 162 return; 163 } 164 165 if (ec) 166 { 167 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 168 messages::internalError(asyncResp->res); 169 return; 170 } 171 172 for (const auto& [objectPath, serviceMap] : subtree) 173 { 174 sdbusplus::message::object_path path(objectPath); 175 if (path.filename() != cableId) 176 { 177 continue; 178 } 179 180 asyncResp->res.jsonValue["@odata.type"] = 181 "#Cable.v1_0_0.Cable"; 182 asyncResp->res.jsonValue["@odata.id"] = 183 boost::urls::format("/redfish/v1/Cables/{}", 184 cableId); 185 asyncResp->res.jsonValue["Id"] = cableId; 186 asyncResp->res.jsonValue["Name"] = "Cable"; 187 asyncResp->res.jsonValue["Status"]["State"] = 188 resource::State::Enabled; 189 190 getCableProperties(asyncResp, objectPath, 191 serviceMap); 192 return; 193 } 194 messages::resourceNotFound(asyncResp->res, "Cable", 195 cableId); 196 }); 197 }); 198 } 199 200 /** 201 * Collection of Cable resource instances 202 */ 203 inline void requestRoutesCableCollection(App& app) 204 { 205 BMCWEB_ROUTE(app, "/redfish/v1/Cables/") 206 .privileges(redfish::privileges::getCableCollection) 207 .methods(boost::beast::http::verb::get)( 208 [&app](const crow::Request& req, 209 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 210 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 211 { 212 return; 213 } 214 asyncResp->res.jsonValue["@odata.type"] = 215 "#CableCollection.CableCollection"; 216 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables"; 217 asyncResp->res.jsonValue["Name"] = "Cable Collection"; 218 asyncResp->res.jsonValue["Description"] = 219 "Collection of Cable Entries"; 220 constexpr std::array<std::string_view, 1> interfaces{ 221 "xyz.openbmc_project.Inventory.Item.Cable"}; 222 collection_util::getCollectionMembers( 223 asyncResp, boost::urls::url("/redfish/v1/Cables"), 224 interfaces, "/xyz/openbmc_project/inventory"); 225 }); 226 } 227 228 } // namespace redfish 229