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