xref: /openbmc/bmcweb/redfish-core/lib/cable.hpp (revision ab8cbe452946895b39620ff09a4df9eb32519b4d)
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  */
fillCableProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)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 
fillCableHealthState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & cableObjectPath,const std::string & service)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  */
getCableProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & cableObjectPath,const dbus::utility::MapperServiceMap & serviceMap)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 
afterHandleCableGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & cableId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)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 
handleCableGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & cableId)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 
handleCableCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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  */
requestRoutesCable(App & app)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  */
requestRoutesCableCollection(App & app)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