1*7bf29ab3SChristopher Meis // SPDX-License-Identifier: Apache-2.0
2*7bf29ab3SChristopher Meis // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3*7bf29ab3SChristopher Meis // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation
4*7bf29ab3SChristopher Meis #pragma once
5*7bf29ab3SChristopher Meis
6*7bf29ab3SChristopher Meis #include "app.hpp"
7*7bf29ab3SChristopher Meis #include "async_resp.hpp"
8*7bf29ab3SChristopher Meis #include "generated/enums/resource.hpp"
9*7bf29ab3SChristopher Meis #include "http_request.hpp"
10*7bf29ab3SChristopher Meis #include "query.hpp"
11*7bf29ab3SChristopher Meis #include "registries/privilege_registry.hpp"
12*7bf29ab3SChristopher Meis
13*7bf29ab3SChristopher Meis namespace redfish
14*7bf29ab3SChristopher Meis {
15*7bf29ab3SChristopher Meis
populateStorageController(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & controllerId,const std::string & connectionName,const std::string & path)16*7bf29ab3SChristopher Meis inline void populateStorageController(
17*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
18*7bf29ab3SChristopher Meis const std::string& controllerId, const std::string& connectionName,
19*7bf29ab3SChristopher Meis const std::string& path)
20*7bf29ab3SChristopher Meis {
21*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.type"] =
22*7bf29ab3SChristopher Meis "#StorageController.v1_6_0.StorageController";
23*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.id"] =
24*7bf29ab3SChristopher Meis boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
25*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId);
26*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Name"] = controllerId;
27*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Id"] = controllerId;
28*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
29*7bf29ab3SChristopher Meis
30*7bf29ab3SChristopher Meis dbus::utility::getProperty<bool>(
31*7bf29ab3SChristopher Meis connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
32*7bf29ab3SChristopher Meis [asyncResp](const boost::system::error_code& ec, bool isPresent) {
33*7bf29ab3SChristopher Meis // this interface isn't necessary, only check it
34*7bf29ab3SChristopher Meis // if we get a good return
35*7bf29ab3SChristopher Meis if (ec)
36*7bf29ab3SChristopher Meis {
37*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to get Present property");
38*7bf29ab3SChristopher Meis return;
39*7bf29ab3SChristopher Meis }
40*7bf29ab3SChristopher Meis if (!isPresent)
41*7bf29ab3SChristopher Meis {
42*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Status"]["State"] =
43*7bf29ab3SChristopher Meis resource::State::Absent;
44*7bf29ab3SChristopher Meis }
45*7bf29ab3SChristopher Meis });
46*7bf29ab3SChristopher Meis
47*7bf29ab3SChristopher Meis asset_utils::getAssetInfo(asyncResp, connectionName, path, ""_json_pointer,
48*7bf29ab3SChristopher Meis false);
49*7bf29ab3SChristopher Meis }
50*7bf29ab3SChristopher Meis
getStorageControllerHandler(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & controllerId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)51*7bf29ab3SChristopher Meis inline void getStorageControllerHandler(
52*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
53*7bf29ab3SChristopher Meis const std::string& controllerId, const boost::system::error_code& ec,
54*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreeResponse& subtree)
55*7bf29ab3SChristopher Meis {
56*7bf29ab3SChristopher Meis if (ec || subtree.empty())
57*7bf29ab3SChristopher Meis {
58*7bf29ab3SChristopher Meis // doesn't have to be there
59*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to handle StorageController");
60*7bf29ab3SChristopher Meis return;
61*7bf29ab3SChristopher Meis }
62*7bf29ab3SChristopher Meis
63*7bf29ab3SChristopher Meis for (const auto& [path, interfaceDict] : subtree)
64*7bf29ab3SChristopher Meis {
65*7bf29ab3SChristopher Meis sdbusplus::message::object_path object(path);
66*7bf29ab3SChristopher Meis std::string id = object.filename();
67*7bf29ab3SChristopher Meis if (id.empty())
68*7bf29ab3SChristopher Meis {
69*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
70*7bf29ab3SChristopher Meis return;
71*7bf29ab3SChristopher Meis }
72*7bf29ab3SChristopher Meis if (id != controllerId)
73*7bf29ab3SChristopher Meis {
74*7bf29ab3SChristopher Meis continue;
75*7bf29ab3SChristopher Meis }
76*7bf29ab3SChristopher Meis
77*7bf29ab3SChristopher Meis if (interfaceDict.size() != 1)
78*7bf29ab3SChristopher Meis {
79*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
80*7bf29ab3SChristopher Meis interfaceDict.size());
81*7bf29ab3SChristopher Meis messages::internalError(asyncResp->res);
82*7bf29ab3SChristopher Meis return;
83*7bf29ab3SChristopher Meis }
84*7bf29ab3SChristopher Meis
85*7bf29ab3SChristopher Meis const std::string& connectionName = interfaceDict.front().first;
86*7bf29ab3SChristopher Meis populateStorageController(asyncResp, controllerId, connectionName,
87*7bf29ab3SChristopher Meis path);
88*7bf29ab3SChristopher Meis }
89*7bf29ab3SChristopher Meis }
90*7bf29ab3SChristopher Meis
populateStorageControllerCollection(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & controllerList)91*7bf29ab3SChristopher Meis inline void populateStorageControllerCollection(
92*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
93*7bf29ab3SChristopher Meis const boost::system::error_code& ec,
94*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
95*7bf29ab3SChristopher Meis {
96*7bf29ab3SChristopher Meis nlohmann::json::array_t members;
97*7bf29ab3SChristopher Meis if (ec || controllerList.empty())
98*7bf29ab3SChristopher Meis {
99*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members"] = std::move(members);
100*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members@odata.count"] = 0;
101*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find any StorageController");
102*7bf29ab3SChristopher Meis return;
103*7bf29ab3SChristopher Meis }
104*7bf29ab3SChristopher Meis
105*7bf29ab3SChristopher Meis for (const std::string& path : controllerList)
106*7bf29ab3SChristopher Meis {
107*7bf29ab3SChristopher Meis std::string id = sdbusplus::message::object_path(path).filename();
108*7bf29ab3SChristopher Meis if (id.empty())
109*7bf29ab3SChristopher Meis {
110*7bf29ab3SChristopher Meis BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
111*7bf29ab3SChristopher Meis return;
112*7bf29ab3SChristopher Meis }
113*7bf29ab3SChristopher Meis nlohmann::json::object_t member;
114*7bf29ab3SChristopher Meis member["@odata.id"] = boost::urls::format(
115*7bf29ab3SChristopher Meis "/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
116*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
117*7bf29ab3SChristopher Meis members.emplace_back(member);
118*7bf29ab3SChristopher Meis }
119*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members@odata.count"] = members.size();
120*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Members"] = std::move(members);
121*7bf29ab3SChristopher Meis }
122*7bf29ab3SChristopher Meis
handleSystemsStorageControllerGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & controllerId)123*7bf29ab3SChristopher Meis inline void handleSystemsStorageControllerGet(
124*7bf29ab3SChristopher Meis App& app, const crow::Request& req,
125*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
126*7bf29ab3SChristopher Meis const std::string& systemName, const std::string& controllerId)
127*7bf29ab3SChristopher Meis {
128*7bf29ab3SChristopher Meis if (!redfish::setUpRedfishRoute(app, req, asyncResp))
129*7bf29ab3SChristopher Meis {
130*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
131*7bf29ab3SChristopher Meis return;
132*7bf29ab3SChristopher Meis }
133*7bf29ab3SChristopher Meis if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
134*7bf29ab3SChristopher Meis {
135*7bf29ab3SChristopher Meis messages::resourceNotFound(asyncResp->res, "ComputerSystem",
136*7bf29ab3SChristopher Meis systemName);
137*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
138*7bf29ab3SChristopher Meis return;
139*7bf29ab3SChristopher Meis }
140*7bf29ab3SChristopher Meis constexpr std::array<std::string_view, 1> interfaces = {
141*7bf29ab3SChristopher Meis "xyz.openbmc_project.Inventory.Item.StorageController"};
142*7bf29ab3SChristopher Meis dbus::utility::getSubTree(
143*7bf29ab3SChristopher Meis "/xyz/openbmc_project/inventory", 0, interfaces,
144*7bf29ab3SChristopher Meis [asyncResp,
145*7bf29ab3SChristopher Meis controllerId](const boost::system::error_code& ec,
146*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreeResponse& subtree) {
147*7bf29ab3SChristopher Meis getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
148*7bf29ab3SChristopher Meis });
149*7bf29ab3SChristopher Meis }
150*7bf29ab3SChristopher Meis
handleSystemsStorageControllerCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)151*7bf29ab3SChristopher Meis inline void handleSystemsStorageControllerCollectionGet(
152*7bf29ab3SChristopher Meis App& app, const crow::Request& req,
153*7bf29ab3SChristopher Meis const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
154*7bf29ab3SChristopher Meis const std::string& systemName)
155*7bf29ab3SChristopher Meis {
156*7bf29ab3SChristopher Meis if (!redfish::setUpRedfishRoute(app, req, asyncResp))
157*7bf29ab3SChristopher Meis {
158*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG(
159*7bf29ab3SChristopher Meis "Failed to setup Redfish Route for StorageController Collection");
160*7bf29ab3SChristopher Meis return;
161*7bf29ab3SChristopher Meis }
162*7bf29ab3SChristopher Meis if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
163*7bf29ab3SChristopher Meis {
164*7bf29ab3SChristopher Meis messages::resourceNotFound(asyncResp->res, "ComputerSystem",
165*7bf29ab3SChristopher Meis systemName);
166*7bf29ab3SChristopher Meis BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
167*7bf29ab3SChristopher Meis return;
168*7bf29ab3SChristopher Meis }
169*7bf29ab3SChristopher Meis
170*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.type"] =
171*7bf29ab3SChristopher Meis "#StorageControllerCollection.StorageControllerCollection";
172*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["@odata.id"] =
173*7bf29ab3SChristopher Meis std::format("/redfish/v1/Systems/{}/Storage/1/Controllers",
174*7bf29ab3SChristopher Meis BMCWEB_REDFISH_SYSTEM_URI_NAME);
175*7bf29ab3SChristopher Meis asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
176*7bf29ab3SChristopher Meis
177*7bf29ab3SChristopher Meis constexpr std::array<std::string_view, 1> interfaces = {
178*7bf29ab3SChristopher Meis "xyz.openbmc_project.Inventory.Item.StorageController"};
179*7bf29ab3SChristopher Meis dbus::utility::getSubTreePaths(
180*7bf29ab3SChristopher Meis "/xyz/openbmc_project/inventory", 0, interfaces,
181*7bf29ab3SChristopher Meis [asyncResp](const boost::system::error_code& ec,
182*7bf29ab3SChristopher Meis const dbus::utility::MapperGetSubTreePathsResponse&
183*7bf29ab3SChristopher Meis controllerList) {
184*7bf29ab3SChristopher Meis populateStorageControllerCollection(asyncResp, ec, controllerList);
185*7bf29ab3SChristopher Meis });
186*7bf29ab3SChristopher Meis }
187*7bf29ab3SChristopher Meis
requestRoutesStorageController(App & app)188*7bf29ab3SChristopher Meis inline void requestRoutesStorageController(App& app)
189*7bf29ab3SChristopher Meis {
190*7bf29ab3SChristopher Meis BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
191*7bf29ab3SChristopher Meis .privileges(redfish::privileges::getStorageControllerCollection)
192*7bf29ab3SChristopher Meis .methods(boost::beast::http::verb::get)(std::bind_front(
193*7bf29ab3SChristopher Meis handleSystemsStorageControllerCollectionGet, std::ref(app)));
194*7bf29ab3SChristopher Meis
195*7bf29ab3SChristopher Meis BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
196*7bf29ab3SChristopher Meis .privileges(redfish::privileges::getStorageController)
197*7bf29ab3SChristopher Meis .methods(boost::beast::http::verb::get)(
198*7bf29ab3SChristopher Meis std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
199*7bf29ab3SChristopher Meis }
200*7bf29ab3SChristopher Meis
201*7bf29ab3SChristopher Meis } // namespace redfish
202