blob: 3a9572ffcd32e10009ec3f8a9a9d584187414a73 [file] [log] [blame]
George Liu9516f412022-09-29 17:21:41 +08001#pragma once
2
3#include "app.hpp"
4#include "dbus_utility.hpp"
5#include "error_messages.hpp"
6#include "query.hpp"
7#include "registries/privilege_registry.hpp"
8#include "utils/chassis_utils.hpp"
9
10#include <boost/url/format.hpp>
11#include <sdbusplus/message/types.hpp>
12
13#include <functional>
14#include <memory>
15#include <optional>
16#include <string>
17#include <string_view>
18
19namespace redfish
20{
21constexpr std::array<std::string_view, 1> fanInterface = {
22 "xyz.openbmc_project.Inventory.Item.Fan"};
23
24inline void
25 updateFanList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26 const std::string& chassisId,
27 const dbus::utility::MapperGetSubTreePathsResponse& fanPaths)
28{
29 nlohmann::json& fanList = asyncResp->res.jsonValue["Members"];
30 for (const std::string& fanPath : fanPaths)
31 {
32 std::string fanName =
33 sdbusplus::message::object_path(fanPath).filename();
34 if (fanName.empty())
35 {
36 continue;
37 }
38
39 nlohmann::json item = nlohmann::json::object();
40 item["@odata.id"] = boost::urls::format(
41 "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans/{}", chassisId,
42 fanName);
43
44 fanList.emplace_back(std::move(item));
45 }
46 asyncResp->res.jsonValue["Members@odata.count"] = fanList.size();
47}
48
49inline void getFanPaths(
50 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
51 const std::optional<std::string>& validChassisPath,
52 const std::function<void(const dbus::utility::MapperGetSubTreePathsResponse&
53 fanPaths)>& callback)
54{
55 sdbusplus::message::object_path endpointPath{*validChassisPath};
56 endpointPath /= "cooled_by";
57
58 dbus::utility::getAssociatedSubTreePaths(
59 endpointPath,
60 sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
61 fanInterface,
62 [asyncResp, callback](
63 const boost::system::error_code& ec,
64 const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
65 if (ec)
66 {
67 if (ec.value() != EBADR)
68 {
69 BMCWEB_LOG_ERROR
70 << "DBUS response error for getAssociatedSubTreePaths "
71 << ec.value();
72 messages::internalError(asyncResp->res);
73 }
74 return;
75 }
76 callback(subtreePaths);
77 });
78}
79
80inline void doFanCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
81 const std::string& chassisId,
82 const std::optional<std::string>& validChassisPath)
83{
84 if (!validChassisPath)
85 {
86 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
87 return;
88 }
89
90 asyncResp->res.addHeader(
91 boost::beast::http::field::link,
92 "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby");
93 asyncResp->res.jsonValue["@odata.type"] = "#FanCollection.FanCollection";
94 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
95 "/redfish/v1/Chassis/{}/ThermalSubsystem/Fans", chassisId);
96 asyncResp->res.jsonValue["Name"] = "Fan Collection";
97 asyncResp->res.jsonValue["Description"] =
98 "The collection of Fan resource instances " + chassisId;
99 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
100 asyncResp->res.jsonValue["Members@odata.count"] = 0;
101
102 getFanPaths(asyncResp, validChassisPath,
103 std::bind_front(updateFanList, asyncResp, chassisId));
104}
105
106inline void
107 handleFanCollectionHead(App& app, const crow::Request& req,
108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
109 const std::string& chassisId)
110{
111 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
112 {
113 return;
114 }
115
116 redfish::chassis_utils::getValidChassisPath(
117 asyncResp, chassisId,
118 [asyncResp,
119 chassisId](const std::optional<std::string>& validChassisPath) {
120 if (!validChassisPath)
121 {
122 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
123 return;
124 }
125 asyncResp->res.addHeader(
126 boost::beast::http::field::link,
127 "</redfish/v1/JsonSchemas/FanCollection/FanCollection.json>; rel=describedby");
128 });
129}
130
131inline void
132 handleFanCollectionGet(App& app, const crow::Request& req,
133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
134 const std::string& chassisId)
135{
136 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
137 {
138 return;
139 }
140
141 redfish::chassis_utils::getValidChassisPath(
142 asyncResp, chassisId,
143 std::bind_front(doFanCollection, asyncResp, chassisId));
144}
145
146inline void requestRoutesFanCollection(App& app)
147{
148 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/")
149 .privileges(redfish::privileges::headFanCollection)
150 .methods(boost::beast::http::verb::head)(
151 std::bind_front(handleFanCollectionHead, std::ref(app)));
152
153 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/")
154 .privileges(redfish::privileges::getFanCollection)
155 .methods(boost::beast::http::verb::get)(
156 std::bind_front(handleFanCollectionGet, std::ref(app)));
157}
158
159} // namespace redfish