Coverage Report

Created: 2026-09-14 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bmcweb/redfish-core/lib/cable.hpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
#pragma once
4
5
#include "app.hpp"
6
#include "async_resp.hpp"
7
#include "dbus_singleton.hpp"
8
#include "dbus_utility.hpp"
9
#include "error_messages.hpp"
10
#include "generated/enums/resource.hpp"
11
#include "http_request.hpp"
12
#include "http_response.hpp"
13
#include "logging.hpp"
14
#include "query.hpp"
15
#include "registries/privilege_registry.hpp"
16
#include "utils/asset_utils.hpp"
17
#include "utils/collection.hpp"
18
#include "utils/dbus_utils.hpp"
19
#include "utils/resource_utils.hpp"
20
21
#include <asm-generic/errno.h>
22
23
#include <boost/beast/http/verb.hpp>
24
#include <boost/system/error_code.hpp>
25
#include <boost/url/format.hpp>
26
#include <boost/url/url.hpp>
27
#include <sdbusplus/message/native_types.hpp>
28
#include <sdbusplus/unpack_properties.hpp>
29
30
#include <array>
31
#include <cmath>
32
#include <functional>
33
#include <memory>
34
#include <string>
35
#include <string_view>
36
37
namespace redfish
38
{
39
40
constexpr std::array<std::string_view, 1> cableInterfaces = {
41
    "xyz.openbmc_project.Inventory.Item.Cable"};
42
43
/**
44
 * @brief Fill cable specific properties.
45
 * @param[in,out]   asyncResp   Async HTTP response.
46
 * @param[in]       ec          Error code corresponding to Async method call.
47
 * @param[in]       properties  List of Cable Properties key/value pairs.
48
 */
49
inline void fillCableProperties(
50
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
51
    const boost::system::error_code& ec,
52
    const dbus::utility::DBusPropertiesMap& properties)
53
0
{
54
0
    if (ec)
55
0
    {
56
0
        BMCWEB_LOG_ERROR("DBUS response error {}", ec);
57
0
        messages::internalError(asyncResp->res);
58
0
        return;
59
0
    }
60
61
0
    const std::string* cableTypeDescription = nullptr;
62
0
    const double* length = nullptr;
63
64
0
    const bool success = sdbusplus::unpackPropertiesNoThrow(
65
0
        dbus_utils::UnpackErrorPrinter(), properties, "CableTypeDescription",
66
0
        cableTypeDescription, "Length", length);
67
68
0
    if (!success)
69
0
    {
70
0
        messages::internalError(asyncResp->res);
71
0
        return;
72
0
    }
73
74
0
    if (cableTypeDescription != nullptr)
75
0
    {
76
0
        asyncResp->res.jsonValue["CableType"] = *cableTypeDescription;
77
0
    }
78
79
0
    if (length != nullptr)
80
0
    {
81
0
        if (!std::isfinite(*length))
82
0
        {
83
            // Cable length is NaN by default, do not throw an error
84
0
            if (!std::isnan(*length))
85
0
            {
86
0
                BMCWEB_LOG_ERROR("Cable length value is invalid");
87
0
                messages::internalError(asyncResp->res);
88
0
                return;
89
0
            }
90
0
        }
91
0
        else
92
0
        {
93
0
            asyncResp->res.jsonValue["LengthMeters"] = *length;
94
0
        }
95
0
    }
96
0
}
97
98
/**
99
 * @brief Api to get Cable properties.
100
 * @param[in,out]   asyncResp       Async HTTP response.
101
 * @param[in]       cableObjectPath Object path of the Cable.
102
 * @param[in]       serviceMap      A map to hold Service and corresponding
103
 * interface list for the given cable id.
104
 */
105
inline void getCableProperties(
106
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
107
    const std::string& cableObjectPath,
108
    const dbus::utility::MapperServiceMap& serviceMap)
109
0
{
110
0
    BMCWEB_LOG_DEBUG("Get Properties for cable {}", cableObjectPath);
111
112
0
    for (const auto& [service, interfaces] : serviceMap)
113
0
    {
114
0
        for (const auto& interface : interfaces)
115
0
        {
116
0
            if (interface == "xyz.openbmc_project.Inventory.Item.Cable")
117
0
            {
118
0
                dbus::utility::getAllProperties(
119
0
                    *crow::connections::systemBus, service, cableObjectPath,
120
0
                    interface, std::bind_front(fillCableProperties, asyncResp));
121
0
            }
122
0
            else if (interface ==
123
0
                     "xyz.openbmc_project.Inventory.Decorator.Asset")
124
0
            {
125
0
                asset_utils::getAssetInfo(asyncResp, service, cableObjectPath,
126
0
                                          ""_json_pointer, false, true);
127
0
            }
128
0
            else if (interface == "xyz.openbmc_project.Inventory.Item")
129
0
            {
130
0
                resource_utils::getResourceState(
131
0
                    asyncResp, service, cableObjectPath, ""_json_pointer);
132
0
            }
133
0
            else if (interface ==
134
0
                     "xyz.openbmc_project.State.Decorator.OperationalStatus")
135
0
            {
136
0
                resource_utils::getResourceHealth(
137
0
                    asyncResp, service, cableObjectPath, ""_json_pointer);
138
0
            }
139
0
        }
140
0
    }
141
0
}
142
143
inline void afterHandleCableGet(
144
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
145
    const std::string& cableId, const boost::system::error_code& ec,
146
    const dbus::utility::MapperGetSubTreeResponse& subtree)
147
0
{
148
0
    if (ec.value() == EBADR)
149
0
    {
150
0
        messages::resourceNotFound(asyncResp->res, "Cable", cableId);
151
0
        return;
152
0
    }
153
154
0
    if (ec)
155
0
    {
156
0
        BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
157
0
        messages::internalError(asyncResp->res);
158
0
        return;
159
0
    }
160
161
0
    for (const auto& [objectPath, serviceMap] : subtree)
162
0
    {
163
0
        sdbusplus::object_path path(objectPath);
164
0
        if (path.filename() != cableId)
165
0
        {
166
0
            continue;
167
0
        }
168
169
0
        asyncResp->res.jsonValue["@odata.type"] = "#Cable.v1_0_0.Cable";
170
0
        asyncResp->res.jsonValue["@odata.id"] =
171
0
            boost::urls::format("/redfish/v1/Cables/{}", cableId);
172
0
        asyncResp->res.jsonValue["Id"] = cableId;
173
0
        asyncResp->res.jsonValue["Name"] = "Cable";
174
0
        asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
175
0
        asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
176
177
0
        getCableProperties(asyncResp, objectPath, serviceMap);
178
0
        return;
179
0
    }
180
0
    messages::resourceNotFound(asyncResp->res, "Cable", cableId);
181
0
}
182
183
inline void handleCableGet(App& app, const crow::Request& req,
184
                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
185
                           const std::string& cableId)
186
0
{
187
0
    if (!redfish::setUpRedfishRoute(app, req, asyncResp))
188
0
    {
189
0
        return;
190
0
    }
191
192
0
    BMCWEB_LOG_DEBUG("Cable Id: {}", cableId);
193
194
0
    dbus::utility::getSubTree(
195
0
        "/xyz/openbmc_project/inventory", 0, cableInterfaces,
196
0
        std::bind_front(afterHandleCableGet, asyncResp, cableId));
197
0
}
198
199
inline void handleCableCollectionGet(
200
    App& app, const crow::Request& req,
201
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
202
0
{
203
0
    if (!redfish::setUpRedfishRoute(app, req, asyncResp))
204
0
    {
205
0
        return;
206
0
    }
207
208
0
    asyncResp->res.jsonValue["@odata.type"] =
209
0
        "#CableCollection.CableCollection";
210
0
    asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Cables";
211
0
    asyncResp->res.jsonValue["Name"] = "Cable Collection";
212
0
    asyncResp->res.jsonValue["Description"] = "Collection of Cable Entries";
213
0
    collection_util::getCollectionMembers(
214
0
        asyncResp, boost::urls::url("/redfish/v1/Cables"), cableInterfaces,
215
0
        "/xyz/openbmc_project/inventory");
216
0
}
217
218
/**
219
 * The Cable schema
220
 */
221
inline void requestRoutesCable(App& app)
222
6.49k
{
223
6.49k
    BMCWEB_ROUTE(app, "/redfish/v1/Cables/<str>/")
224
6.49k
        .privileges(redfish::privileges::getCable)
225
6.49k
        .methods(boost::beast::http::verb::get)(
226
6.49k
            std::bind_front(handleCableGet, std::ref(app)));
227
6.49k
}
228
229
/**
230
 * Collection of Cable resource instances
231
 */
232
inline void requestRoutesCableCollection(App& app)
233
6.49k
{
234
6.49k
    BMCWEB_ROUTE(app, "/redfish/v1/Cables/")
235
6.49k
        .privileges(redfish::privileges::getCableCollection)
236
6.49k
        .methods(boost::beast::http::verb::get)(
237
6.49k
            std::bind_front(handleCableCollectionGet, std::ref(app)));
238
6.49k
}
239
240
} // namespace redfish