140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 39c929beaSShantappa Teekappanavar #pragma once 47a1dbc48SGeorge Liu 5d7857201SEd Tanous #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 7d7857201SEd Tanous #include "dbus_singleton.hpp" 87a1dbc48SGeorge Liu #include "dbus_utility.hpp" 9d7857201SEd Tanous #include "error_messages.hpp" 10539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 11d7857201SEd Tanous #include "http_request.hpp" 12d7857201SEd Tanous #include "http_response.hpp" 13d7857201SEd Tanous #include "logging.hpp" 143ccb3adbSEd Tanous #include "query.hpp" 153ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 163ccb3adbSEd Tanous #include "utils/collection.hpp" 173ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 187a1dbc48SGeorge Liu 19d7857201SEd Tanous #include <asm-generic/errno.h> 20d7857201SEd Tanous 21d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 22e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 23ef4c65b7SEd Tanous #include <boost/url/format.hpp> 24d7857201SEd Tanous #include <boost/url/url.hpp> 25d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 2689474494SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 279c929beaSShantappa Teekappanavar 287a1dbc48SGeorge Liu #include <array> 29d7857201SEd Tanous #include <cmath> 30*ab8cbe45SMyung Bae #include <functional> 31d7857201SEd Tanous #include <memory> 32d7857201SEd Tanous #include <string> 337a1dbc48SGeorge Liu #include <string_view> 347a1dbc48SGeorge Liu 359c929beaSShantappa Teekappanavar namespace redfish 369c929beaSShantappa Teekappanavar { 37*ab8cbe45SMyung Bae 38*ab8cbe45SMyung Bae constexpr std::array<std::string_view, 1> cableInterfaces = { 39*ab8cbe45SMyung Bae "xyz.openbmc_project.Inventory.Item.Cable"}; 40*ab8cbe45SMyung Bae 419c929beaSShantappa Teekappanavar /** 429c929beaSShantappa Teekappanavar * @brief Fill cable specific properties. 43*ab8cbe45SMyung Bae * @param[in,out] asyncResp Async HTTP response. 449c929beaSShantappa Teekappanavar * @param[in] ec Error code corresponding to Async method call. 459c929beaSShantappa Teekappanavar * @param[in] properties List of Cable Properties key/value pairs. 469c929beaSShantappa Teekappanavar */ 47bd79bce8SPatrick Williams inline void fillCableProperties( 48*ab8cbe45SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 49*ab8cbe45SMyung Bae const boost::system::error_code& ec, 509c929beaSShantappa Teekappanavar const dbus::utility::DBusPropertiesMap& properties) 519c929beaSShantappa Teekappanavar { 529c929beaSShantappa Teekappanavar if (ec) 539c929beaSShantappa Teekappanavar { 54f933a6a0SGunnar Mills BMCWEB_LOG_ERROR("DBUS response error {}", ec); 55*ab8cbe45SMyung Bae messages::internalError(asyncResp->res); 569c929beaSShantappa Teekappanavar return; 579c929beaSShantappa Teekappanavar } 589c929beaSShantappa Teekappanavar 5989474494SKrzysztof Grobelny const std::string* cableTypeDescription = nullptr; 6089474494SKrzysztof Grobelny const double* length = nullptr; 6189474494SKrzysztof Grobelny 6289474494SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 6389474494SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription", 6489474494SKrzysztof Grobelny cableTypeDescription, "Length", length); 6589474494SKrzysztof Grobelny 6689474494SKrzysztof Grobelny if (!success) 679c929beaSShantappa Teekappanavar { 68*ab8cbe45SMyung Bae messages::internalError(asyncResp->res); 699c929beaSShantappa Teekappanavar return; 709c929beaSShantappa Teekappanavar } 7189474494SKrzysztof Grobelny 7289474494SKrzysztof Grobelny if (cableTypeDescription != nullptr) 7389474494SKrzysztof Grobelny { 74*ab8cbe45SMyung Bae asyncResp->res.jsonValue["CableType"] = *cableTypeDescription; 759c929beaSShantappa Teekappanavar } 769c929beaSShantappa Teekappanavar 7789474494SKrzysztof Grobelny if (length != nullptr) 789c929beaSShantappa Teekappanavar { 7989474494SKrzysztof Grobelny if (!std::isfinite(*length)) 809c929beaSShantappa Teekappanavar { 81043360d0SShantappa Teekappanavar // Cable length is NaN by default, do not throw an error 82043360d0SShantappa Teekappanavar if (!std::isnan(*length)) 8389474494SKrzysztof Grobelny { 84*ab8cbe45SMyung Bae BMCWEB_LOG_ERROR("Cable length value is invalid"); 85*ab8cbe45SMyung Bae messages::internalError(asyncResp->res); 869c929beaSShantappa Teekappanavar return; 879c929beaSShantappa Teekappanavar } 88043360d0SShantappa Teekappanavar } 89043360d0SShantappa Teekappanavar else 90043360d0SShantappa Teekappanavar { 91*ab8cbe45SMyung Bae asyncResp->res.jsonValue["LengthMeters"] = *length; 929c929beaSShantappa Teekappanavar } 939c929beaSShantappa Teekappanavar } 94043360d0SShantappa Teekappanavar } 959c929beaSShantappa Teekappanavar 96*ab8cbe45SMyung Bae inline void fillCableHealthState( 97*ab8cbe45SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 98*ab8cbe45SMyung Bae const std::string& cableObjectPath, const std::string& service) 99*ab8cbe45SMyung Bae { 100*ab8cbe45SMyung Bae dbus::utility::getProperty<bool>( 101*ab8cbe45SMyung Bae *crow::connections::systemBus, service, cableObjectPath, 102*ab8cbe45SMyung Bae "xyz.openbmc_project.Inventory.Item", "Present", 103*ab8cbe45SMyung Bae [asyncResp, 104*ab8cbe45SMyung Bae cableObjectPath](const boost::system::error_code& ec, bool present) { 105*ab8cbe45SMyung Bae if (ec) 106*ab8cbe45SMyung Bae { 107*ab8cbe45SMyung Bae if (ec.value() != EBADR) 108*ab8cbe45SMyung Bae { 109*ab8cbe45SMyung Bae BMCWEB_LOG_ERROR( 110*ab8cbe45SMyung Bae "get presence failed for Cable {} with error {}", 111*ab8cbe45SMyung Bae cableObjectPath, ec.value()); 112*ab8cbe45SMyung Bae messages::internalError(asyncResp->res); 113*ab8cbe45SMyung Bae } 114*ab8cbe45SMyung Bae return; 115*ab8cbe45SMyung Bae } 116*ab8cbe45SMyung Bae 117*ab8cbe45SMyung Bae if (!present) 118*ab8cbe45SMyung Bae { 119*ab8cbe45SMyung Bae asyncResp->res.jsonValue["Status"]["State"] = 120*ab8cbe45SMyung Bae resource::State::Absent; 121*ab8cbe45SMyung Bae } 122*ab8cbe45SMyung Bae }); 123*ab8cbe45SMyung Bae } 124*ab8cbe45SMyung Bae 1259c929beaSShantappa Teekappanavar /** 1269c929beaSShantappa Teekappanavar * @brief Api to get Cable properties. 1279c929beaSShantappa Teekappanavar * @param[in,out] asyncResp Async HTTP response. 1289c929beaSShantappa Teekappanavar * @param[in] cableObjectPath Object path of the Cable. 1299c929beaSShantappa Teekappanavar * @param[in] serviceMap A map to hold Service and corresponding 1309c929beaSShantappa Teekappanavar * interface list for the given cable id. 1319c929beaSShantappa Teekappanavar */ 132504af5a0SPatrick Williams inline void getCableProperties( 133504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1349c929beaSShantappa Teekappanavar const std::string& cableObjectPath, 1359c929beaSShantappa Teekappanavar const dbus::utility::MapperServiceMap& serviceMap) 1369c929beaSShantappa Teekappanavar { 13762598e31SEd Tanous BMCWEB_LOG_DEBUG("Get Properties for cable {}", cableObjectPath); 1389c929beaSShantappa Teekappanavar 1399c929beaSShantappa Teekappanavar for (const auto& [service, interfaces] : serviceMap) 1409c929beaSShantappa Teekappanavar { 1419c929beaSShantappa Teekappanavar for (const auto& interface : interfaces) 1429c929beaSShantappa Teekappanavar { 1430c2ba59dSAkshit Shah if (interface == "xyz.openbmc_project.Inventory.Item.Cable") 1449c929beaSShantappa Teekappanavar { 145deae6a78SEd Tanous dbus::utility::getAllProperties( 14689474494SKrzysztof Grobelny *crow::connections::systemBus, service, cableObjectPath, 147*ab8cbe45SMyung Bae interface, std::bind_front(fillCableProperties, asyncResp)); 1489c929beaSShantappa Teekappanavar } 1490c2ba59dSAkshit Shah else if (interface == "xyz.openbmc_project.Inventory.Item") 1500c2ba59dSAkshit Shah { 151*ab8cbe45SMyung Bae fillCableHealthState(asyncResp, cableObjectPath, service); 1520c2ba59dSAkshit Shah } 1530c2ba59dSAkshit Shah } 1549c929beaSShantappa Teekappanavar } 1559c929beaSShantappa Teekappanavar } 1569c929beaSShantappa Teekappanavar 157*ab8cbe45SMyung Bae inline void afterHandleCableGet( 1589c929beaSShantappa Teekappanavar const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 159*ab8cbe45SMyung Bae const std::string& cableId, const boost::system::error_code& ec, 160*ab8cbe45SMyung Bae const dbus::utility::MapperGetSubTreeResponse& subtree) 16145ca1b86SEd Tanous { 1629c929beaSShantappa Teekappanavar if (ec.value() == EBADR) 1639c929beaSShantappa Teekappanavar { 164*ab8cbe45SMyung Bae messages::resourceNotFound(asyncResp->res, "Cable", cableId); 1659c929beaSShantappa Teekappanavar return; 1669c929beaSShantappa Teekappanavar } 1679c929beaSShantappa Teekappanavar 1689c929beaSShantappa Teekappanavar if (ec) 1699c929beaSShantappa Teekappanavar { 170*ab8cbe45SMyung Bae BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 1719c929beaSShantappa Teekappanavar messages::internalError(asyncResp->res); 1729c929beaSShantappa Teekappanavar return; 1739c929beaSShantappa Teekappanavar } 1749c929beaSShantappa Teekappanavar 1759c929beaSShantappa Teekappanavar for (const auto& [objectPath, serviceMap] : subtree) 1769c929beaSShantappa Teekappanavar { 1779c929beaSShantappa Teekappanavar sdbusplus::message::object_path path(objectPath); 1789c929beaSShantappa Teekappanavar if (path.filename() != cableId) 1799c929beaSShantappa Teekappanavar { 1809c929beaSShantappa Teekappanavar continue; 1819c929beaSShantappa Teekappanavar } 1829c929beaSShantappa Teekappanavar 183*ab8cbe45SMyung Bae asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable"; 1849c929beaSShantappa Teekappanavar asyncResp->res.jsonValue["@odata.id"] = 185*ab8cbe45SMyung Bae boost::urls::format("/redfish/v1/Cables/{}", cableId); 1869c929beaSShantappa Teekappanavar asyncResp->res.jsonValue["Id"] = cableId; 1879c929beaSShantappa Teekappanavar asyncResp->res.jsonValue["Name"] = "Cable"; 188*ab8cbe45SMyung Bae asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 1899c929beaSShantappa Teekappanavar 190*ab8cbe45SMyung Bae getCableProperties(asyncResp, objectPath, serviceMap); 1919c929beaSShantappa Teekappanavar return; 1929c929beaSShantappa Teekappanavar } 193*ab8cbe45SMyung Bae messages::resourceNotFound(asyncResp->res, "Cable", cableId); 194*ab8cbe45SMyung Bae } 195*ab8cbe45SMyung Bae 196*ab8cbe45SMyung Bae inline void handleCableGet(App& app, const crow::Request& req, 197*ab8cbe45SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 198*ab8cbe45SMyung Bae const std::string& cableId) 199*ab8cbe45SMyung Bae { 200*ab8cbe45SMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 201*ab8cbe45SMyung Bae { 202*ab8cbe45SMyung Bae return; 203*ab8cbe45SMyung Bae } 204*ab8cbe45SMyung Bae 205*ab8cbe45SMyung Bae BMCWEB_LOG_DEBUG("Cable Id: {}", cableId); 206*ab8cbe45SMyung Bae 207*ab8cbe45SMyung Bae dbus::utility::getSubTree( 208*ab8cbe45SMyung Bae "/xyz/openbmc_project/inventory", 0, cableInterfaces, 209*ab8cbe45SMyung Bae std::bind_front(afterHandleCableGet, asyncResp, cableId)); 210*ab8cbe45SMyung Bae } 211*ab8cbe45SMyung Bae 212*ab8cbe45SMyung Bae inline void handleCableCollectionGet( 213*ab8cbe45SMyung Bae App& app, const crow::Request& req, 214*ab8cbe45SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 215*ab8cbe45SMyung Bae { 216*ab8cbe45SMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 217*ab8cbe45SMyung Bae { 218*ab8cbe45SMyung Bae return; 219*ab8cbe45SMyung Bae } 220*ab8cbe45SMyung Bae 221*ab8cbe45SMyung Bae asyncResp->res.jsonValue["@odata.type"] = 222*ab8cbe45SMyung Bae "#CableCollection.CableCollection"; 223*ab8cbe45SMyung Bae asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables"; 224*ab8cbe45SMyung Bae asyncResp->res.jsonValue["Name"] = "Cable Collection"; 225*ab8cbe45SMyung Bae asyncResp->res.jsonValue["Description"] = "Collection of Cable Entries"; 226*ab8cbe45SMyung Bae collection_util::getCollectionMembers( 227*ab8cbe45SMyung Bae asyncResp, boost::urls::url("/redfish/v1/Cables"), cableInterfaces, 228*ab8cbe45SMyung Bae "/xyz/openbmc_project/inventory"); 229*ab8cbe45SMyung Bae } 230*ab8cbe45SMyung Bae 231*ab8cbe45SMyung Bae /** 232*ab8cbe45SMyung Bae * The Cable schema 233*ab8cbe45SMyung Bae */ 234*ab8cbe45SMyung Bae inline void requestRoutesCable(App& app) 235*ab8cbe45SMyung Bae { 236*ab8cbe45SMyung Bae BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/") 237*ab8cbe45SMyung Bae .privileges(redfish::privileges::getCable) 238*ab8cbe45SMyung Bae .methods(boost::beast::http::verb::get)( 239*ab8cbe45SMyung Bae std::bind_front(handleCableGet, std::ref(app))); 2409c929beaSShantappa Teekappanavar } 2419c929beaSShantappa Teekappanavar 2429c929beaSShantappa Teekappanavar /** 2439c929beaSShantappa Teekappanavar * Collection of Cable resource instances 2449c929beaSShantappa Teekappanavar */ 2459c929beaSShantappa Teekappanavar inline void requestRoutesCableCollection(App& app) 2469c929beaSShantappa Teekappanavar { 2479c929beaSShantappa Teekappanavar BMCWEB_ROUTE(app, "/redfish/v1/Cables/") 2489c929beaSShantappa Teekappanavar .privileges(redfish::privileges::getCableCollection) 2499c929beaSShantappa Teekappanavar .methods(boost::beast::http::verb::get)( 250*ab8cbe45SMyung Bae std::bind_front(handleCableCollectionGet, std::ref(app))); 2519c929beaSShantappa Teekappanavar } 2529c929beaSShantappa Teekappanavar 2539c929beaSShantappa Teekappanavar } // namespace redfish 254