xref: /openbmc/bmcweb/features/redfish/lib/storage.hpp (revision be13cecef3c072f16b6559a52722ff9c6385b77b)
1a25aeccfSNikhil Potade /*
2a25aeccfSNikhil Potade // Copyright (c) 2019 Intel Corporation
3a25aeccfSNikhil Potade //
4a25aeccfSNikhil Potade // Licensed under the Apache License, Version 2.0 (the "License");
5a25aeccfSNikhil Potade // you may not use this file except in compliance with the License.
6a25aeccfSNikhil Potade // You may obtain a copy of the License at
7a25aeccfSNikhil Potade //
8a25aeccfSNikhil Potade //      http://www.apache.org/licenses/LICENSE-2.0
9a25aeccfSNikhil Potade //
10a25aeccfSNikhil Potade // Unless required by applicable law or agreed to in writing, software
11a25aeccfSNikhil Potade // distributed under the License is distributed on an "AS IS" BASIS,
12a25aeccfSNikhil Potade // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a25aeccfSNikhil Potade // See the License for the specific language governing permissions and
14a25aeccfSNikhil Potade // limitations under the License.
15a25aeccfSNikhil Potade */
16a25aeccfSNikhil Potade #pragma once
17a25aeccfSNikhil Potade 
18a25aeccfSNikhil Potade #include <node.hpp>
19a25aeccfSNikhil Potade 
20a25aeccfSNikhil Potade namespace redfish
21a25aeccfSNikhil Potade {
22a25aeccfSNikhil Potade class StorageCollection : public Node
23a25aeccfSNikhil Potade {
24a25aeccfSNikhil Potade   public:
25a25aeccfSNikhil Potade     StorageCollection(CrowApp &app) :
26a25aeccfSNikhil Potade         Node(app, "/redfish/v1/Systems/system/Storage/")
27a25aeccfSNikhil Potade     {
28a25aeccfSNikhil Potade         entityPrivileges = {
29a25aeccfSNikhil Potade             {boost::beast::http::verb::get, {{"Login"}}},
30a25aeccfSNikhil Potade             {boost::beast::http::verb::head, {{"Login"}}},
31a25aeccfSNikhil Potade             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
32a25aeccfSNikhil Potade             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
33a25aeccfSNikhil Potade             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
34a25aeccfSNikhil Potade             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
35a25aeccfSNikhil Potade     }
36a25aeccfSNikhil Potade 
37a25aeccfSNikhil Potade   private:
38a25aeccfSNikhil Potade     void doGet(crow::Response &res, const crow::Request &req,
39a25aeccfSNikhil Potade                const std::vector<std::string> &params) override
40a25aeccfSNikhil Potade     {
41a25aeccfSNikhil Potade         res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection";
42a25aeccfSNikhil Potade         res.jsonValue["@odata.context"] =
43a25aeccfSNikhil Potade             "/redfish/v1/$metadata#StorageCollection.StorageCollection";
44a25aeccfSNikhil Potade         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage";
45a25aeccfSNikhil Potade         res.jsonValue["Name"] = "Storage Collection";
46a25aeccfSNikhil Potade         res.jsonValue["Members"] = {
47a25aeccfSNikhil Potade             {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}};
48a25aeccfSNikhil Potade         res.jsonValue["Members@odata.count"] = 1;
49a25aeccfSNikhil Potade         res.end();
50a25aeccfSNikhil Potade     }
51a25aeccfSNikhil Potade };
52a25aeccfSNikhil Potade 
53a25aeccfSNikhil Potade class Storage : public Node
54a25aeccfSNikhil Potade {
55a25aeccfSNikhil Potade   public:
56a25aeccfSNikhil Potade     Storage(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/Storage/1")
57a25aeccfSNikhil Potade     {
58a25aeccfSNikhil Potade         entityPrivileges = {
59a25aeccfSNikhil Potade             {boost::beast::http::verb::get, {{"Login"}}},
60a25aeccfSNikhil Potade             {boost::beast::http::verb::head, {{"Login"}}},
61a25aeccfSNikhil Potade             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
62a25aeccfSNikhil Potade             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
63a25aeccfSNikhil Potade             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
64a25aeccfSNikhil Potade             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
65a25aeccfSNikhil Potade     }
66a25aeccfSNikhil Potade 
67a25aeccfSNikhil Potade   private:
68a25aeccfSNikhil Potade     void doGet(crow::Response &res, const crow::Request &req,
69a25aeccfSNikhil Potade                const std::vector<std::string> &params) override
70a25aeccfSNikhil Potade     {
71a25aeccfSNikhil Potade         res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
72a25aeccfSNikhil Potade         res.jsonValue["@odata.context"] =
73a25aeccfSNikhil Potade             "/redfish/v1/$metadata#Storage.Storage";
74a25aeccfSNikhil Potade         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
75a25aeccfSNikhil Potade         res.jsonValue["Name"] = "Storage Controller";
76a25aeccfSNikhil Potade         res.jsonValue["Id"] = "1";
77a25aeccfSNikhil Potade 
78a25aeccfSNikhil Potade         auto asyncResp = std::make_shared<AsyncResp>(res);
79a25aeccfSNikhil Potade         crow::connections::systemBus->async_method_call(
80a25aeccfSNikhil Potade             [asyncResp](const boost::system::error_code ec,
81a25aeccfSNikhil Potade                         const std::vector<std::string> &storageList) {
82a25aeccfSNikhil Potade                 nlohmann::json &storageArray =
83a25aeccfSNikhil Potade                     asyncResp->res.jsonValue["Drives"];
84a25aeccfSNikhil Potade                 storageArray = nlohmann::json::array();
85a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["Drives@odata.count"] = 0;
86a25aeccfSNikhil Potade                 if (ec)
87a25aeccfSNikhil Potade                 {
88a25aeccfSNikhil Potade                     BMCWEB_LOG_ERROR << "Drive mapper call error";
89a25aeccfSNikhil Potade                     messages::internalError(asyncResp->res);
90a25aeccfSNikhil Potade                     return;
91a25aeccfSNikhil Potade                 }
92a25aeccfSNikhil Potade                 for (const std::string &objpath : storageList)
93a25aeccfSNikhil Potade                 {
94a25aeccfSNikhil Potade                     std::size_t lastPos = objpath.rfind("/");
95a25aeccfSNikhil Potade                     if (lastPos == std::string::npos ||
96a25aeccfSNikhil Potade                         (objpath.size() <= lastPos + 1))
97a25aeccfSNikhil Potade                     {
98a25aeccfSNikhil Potade                         BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
99a25aeccfSNikhil Potade                         continue;
100a25aeccfSNikhil Potade                     }
101a25aeccfSNikhil Potade 
102a25aeccfSNikhil Potade                     storageArray.push_back(
103a25aeccfSNikhil Potade                         {{"@odata.id",
104*be13ceceSJames Feist                           "/redfish/v1/Systems/system/Storage/1/Drives/" +
105a25aeccfSNikhil Potade                               objpath.substr(lastPos + 1)}});
106a25aeccfSNikhil Potade                 }
107a25aeccfSNikhil Potade 
108a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["Drives@odata.count"] =
109a25aeccfSNikhil Potade                     storageArray.size();
110a25aeccfSNikhil Potade             },
111a25aeccfSNikhil Potade             "xyz.openbmc_project.ObjectMapper",
112a25aeccfSNikhil Potade             "/xyz/openbmc_project/object_mapper",
113a25aeccfSNikhil Potade             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
114a25aeccfSNikhil Potade             "/xyz/openbmc_project/inventory", int32_t(0),
115a25aeccfSNikhil Potade             std::array<const char *, 1>{
116a25aeccfSNikhil Potade                 "xyz.openbmc_project.Inventory.Item.Drive"});
117a25aeccfSNikhil Potade     }
118a25aeccfSNikhil Potade };
119a25aeccfSNikhil Potade 
120a25aeccfSNikhil Potade class Drive : public Node
121a25aeccfSNikhil Potade {
122a25aeccfSNikhil Potade   public:
123a25aeccfSNikhil Potade     Drive(CrowApp &app) :
124*be13ceceSJames Feist         Node(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/",
125a25aeccfSNikhil Potade              std::string())
126a25aeccfSNikhil Potade     {
127a25aeccfSNikhil Potade         entityPrivileges = {
128a25aeccfSNikhil Potade             {boost::beast::http::verb::get, {{"Login"}}},
129a25aeccfSNikhil Potade             {boost::beast::http::verb::head, {{"Login"}}},
130a25aeccfSNikhil Potade             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
131a25aeccfSNikhil Potade             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
132a25aeccfSNikhil Potade             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
133a25aeccfSNikhil Potade             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
134a25aeccfSNikhil Potade     }
135a25aeccfSNikhil Potade 
136a25aeccfSNikhil Potade   private:
137a25aeccfSNikhil Potade     void doGet(crow::Response &res, const crow::Request &req,
138a25aeccfSNikhil Potade                const std::vector<std::string> &params) override
139a25aeccfSNikhil Potade     {
140a25aeccfSNikhil Potade         const std::string &driveId = params[0];
141a25aeccfSNikhil Potade 
142a25aeccfSNikhil Potade         auto asyncResp = std::make_shared<AsyncResp>(res);
143a25aeccfSNikhil Potade 
144a25aeccfSNikhil Potade         crow::connections::systemBus->async_method_call(
145a25aeccfSNikhil Potade             [asyncResp, driveId](
146a25aeccfSNikhil Potade                 const boost::system::error_code ec,
147a25aeccfSNikhil Potade                 const std::vector<std::pair<
148a25aeccfSNikhil Potade                     std::string, std::vector<std::pair<
149a25aeccfSNikhil Potade                                      std::string, std::vector<std::string>>>>>
150a25aeccfSNikhil Potade                     &subtree) {
151a25aeccfSNikhil Potade                 if (ec)
152a25aeccfSNikhil Potade                 {
153a25aeccfSNikhil Potade                     BMCWEB_LOG_ERROR << "Drive mapper call error";
154a25aeccfSNikhil Potade                     messages::internalError(asyncResp->res);
155a25aeccfSNikhil Potade                     return;
156a25aeccfSNikhil Potade                 }
157a25aeccfSNikhil Potade 
158a25aeccfSNikhil Potade                 auto object = std::find_if(
159a25aeccfSNikhil Potade                     subtree.begin(), subtree.end(), [&driveId](auto &object) {
160a25aeccfSNikhil Potade                         const std::string &path = object.first;
161a25aeccfSNikhil Potade                         return boost::ends_with(path, "/" + driveId);
162a25aeccfSNikhil Potade                     });
163a25aeccfSNikhil Potade 
164a25aeccfSNikhil Potade                 if (object == subtree.end())
165a25aeccfSNikhil Potade                 {
166a25aeccfSNikhil Potade                     messages::resourceNotFound(asyncResp->res, "Drive",
167a25aeccfSNikhil Potade                                                driveId);
168a25aeccfSNikhil Potade                     return;
169a25aeccfSNikhil Potade                 }
170a25aeccfSNikhil Potade 
171a25aeccfSNikhil Potade                 const std::string &path = object->first;
172a25aeccfSNikhil Potade                 const std::vector<
173a25aeccfSNikhil Potade                     std::pair<std::string, std::vector<std::string>>>
174a25aeccfSNikhil Potade                     &connectionNames = object->second;
175a25aeccfSNikhil Potade 
176a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
177a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["@odata.context"] =
178a25aeccfSNikhil Potade                     "/redfish/v1/$metadata#Drive.Drive";
179a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["@odata.id"] =
180*be13ceceSJames Feist                     "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId;
181a25aeccfSNikhil Potade 
182a25aeccfSNikhil Potade                 if (connectionNames.size() != 1)
183a25aeccfSNikhil Potade                 {
184a25aeccfSNikhil Potade                     BMCWEB_LOG_ERROR << "Connection size "
185a25aeccfSNikhil Potade                                      << connectionNames.size()
186a25aeccfSNikhil Potade                                      << ", greater than 1";
187a25aeccfSNikhil Potade                     messages::internalError(asyncResp->res);
188a25aeccfSNikhil Potade                     return;
189a25aeccfSNikhil Potade                 }
190a25aeccfSNikhil Potade 
191a25aeccfSNikhil Potade                 getMainChassisId(
192a25aeccfSNikhil Potade                     asyncResp, [](const std::string &chassisId,
193a25aeccfSNikhil Potade                                   std::shared_ptr<AsyncResp> aRsp) {
194a25aeccfSNikhil Potade                         aRsp->res.jsonValue["Links"]["Chassis"] = {
195a25aeccfSNikhil Potade                             {"@odata.id", "/redfish/v1/Chassis/" + chassisId}};
196a25aeccfSNikhil Potade                     });
197a25aeccfSNikhil Potade 
198a25aeccfSNikhil Potade                 const std::string &connectionName = connectionNames[0].first;
199a25aeccfSNikhil Potade                 crow::connections::systemBus->async_method_call(
200a25aeccfSNikhil Potade                     [asyncResp,
201a25aeccfSNikhil Potade                      driveId](const boost::system::error_code ec,
202a25aeccfSNikhil Potade                               const std::vector<std::pair<
203a25aeccfSNikhil Potade                                   std::string,
204a25aeccfSNikhil Potade                                   std::variant<bool, std::string, uint64_t>>>
205a25aeccfSNikhil Potade                                   &propertiesList) {
206a25aeccfSNikhil Potade                         if (ec)
207a25aeccfSNikhil Potade                         {
208a25aeccfSNikhil Potade                             // this interface isn't necessary
209a25aeccfSNikhil Potade                             return;
210a25aeccfSNikhil Potade                         }
211a25aeccfSNikhil Potade                         for (const std::pair<std::string,
212a25aeccfSNikhil Potade                                              std::variant<bool, std::string,
213a25aeccfSNikhil Potade                                                           uint64_t>> &property :
214a25aeccfSNikhil Potade                              propertiesList)
215a25aeccfSNikhil Potade                         {
216a25aeccfSNikhil Potade                             // Store DBus properties that are also
217a25aeccfSNikhil Potade                             // Redfish properties with same name and a
218a25aeccfSNikhil Potade                             // string value
219a25aeccfSNikhil Potade                             const std::string &propertyName = property.first;
220a25aeccfSNikhil Potade                             if ((propertyName == "PartNumber") ||
221a25aeccfSNikhil Potade                                 (propertyName == "SerialNumber") ||
222a25aeccfSNikhil Potade                                 (propertyName == "Manufacturer") ||
223a25aeccfSNikhil Potade                                 (propertyName == "Model"))
224a25aeccfSNikhil Potade                             {
225a25aeccfSNikhil Potade                                 const std::string *value =
226a25aeccfSNikhil Potade                                     std::get_if<std::string>(&property.second);
227a25aeccfSNikhil Potade                                 if (value == nullptr)
228a25aeccfSNikhil Potade                                 {
229a25aeccfSNikhil Potade                                     // illegal property
230a25aeccfSNikhil Potade                                     messages::internalError(asyncResp->res);
231a25aeccfSNikhil Potade                                     continue;
232a25aeccfSNikhil Potade                                 }
233a25aeccfSNikhil Potade                                 asyncResp->res.jsonValue[propertyName] = *value;
234a25aeccfSNikhil Potade                             }
235a25aeccfSNikhil Potade                         }
236a25aeccfSNikhil Potade                         asyncResp->res.jsonValue["Name"] = driveId;
237a25aeccfSNikhil Potade                         asyncResp->res.jsonValue["Id"] = driveId;
238a25aeccfSNikhil Potade                     },
239a25aeccfSNikhil Potade                     connectionName, path, "org.freedesktop.DBus.Properties",
240a25aeccfSNikhil Potade                     "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
241a25aeccfSNikhil Potade 
242a25aeccfSNikhil Potade                 // default it to Enabled
243a25aeccfSNikhil Potade                 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
244a25aeccfSNikhil Potade 
245a25aeccfSNikhil Potade                 crow::connections::systemBus->async_method_call(
246a25aeccfSNikhil Potade                     [asyncResp, path](const boost::system::error_code ec,
247a25aeccfSNikhil Potade                                       const std::variant<bool> present) {
248a25aeccfSNikhil Potade                         // this interface isn't necessary, only check it if we
249a25aeccfSNikhil Potade                         // get a good return
250a25aeccfSNikhil Potade                         if (!ec)
251a25aeccfSNikhil Potade                         {
252a25aeccfSNikhil Potade                             const bool *enabled = std::get_if<bool>(&present);
253a25aeccfSNikhil Potade                             if (enabled == nullptr)
254a25aeccfSNikhil Potade                             {
255a25aeccfSNikhil Potade                                 BMCWEB_LOG_DEBUG << "Illegal property present";
256a25aeccfSNikhil Potade                                 messages::internalError(asyncResp->res);
257a25aeccfSNikhil Potade                                 return;
258a25aeccfSNikhil Potade                             }
259a25aeccfSNikhil Potade                             if (!(*enabled))
260a25aeccfSNikhil Potade                             {
261a25aeccfSNikhil Potade                                 asyncResp->res.jsonValue["Status"]["State"] =
262a25aeccfSNikhil Potade                                     "Disabled";
263a25aeccfSNikhil Potade                                 return;
264a25aeccfSNikhil Potade                             }
265a25aeccfSNikhil Potade                         }
266a25aeccfSNikhil Potade 
267a25aeccfSNikhil Potade                         // only populate if Enabled, assume enabled unless item
268a25aeccfSNikhil Potade                         // interface says otherwise
269a25aeccfSNikhil Potade                         auto health =
270a25aeccfSNikhil Potade                             std::make_shared<HealthPopulate>(asyncResp);
271a25aeccfSNikhil Potade                         health->inventory = std::vector<std::string>{path};
272a25aeccfSNikhil Potade 
273a25aeccfSNikhil Potade                         health->populate();
274a25aeccfSNikhil Potade                     },
275a25aeccfSNikhil Potade                     connectionName, path, "org.freedesktop.DBus.Properties",
276a25aeccfSNikhil Potade                     "Get", "xyz.openbmc_project.Inventory.Item", "Present");
27722984074SJames Feist 
27822984074SJames Feist                 crow::connections::systemBus->async_method_call(
27922984074SJames Feist                     [asyncResp](const boost::system::error_code ec,
28022984074SJames Feist                                 const std::variant<bool> rebuilding) {
28122984074SJames Feist                         // this interface isn't necessary, only check it if we
28222984074SJames Feist                         // get a good return
28322984074SJames Feist                         if (ec)
28422984074SJames Feist                         {
28522984074SJames Feist                             return;
28622984074SJames Feist                         }
28722984074SJames Feist                         const bool *updating = std::get_if<bool>(&rebuilding);
28822984074SJames Feist                         if (updating == nullptr)
28922984074SJames Feist                         {
29022984074SJames Feist                             BMCWEB_LOG_DEBUG << "Illegal property present";
29122984074SJames Feist                             messages::internalError(asyncResp->res);
29222984074SJames Feist                             return;
29322984074SJames Feist                         }
29422984074SJames Feist 
29522984074SJames Feist                         // updating and disabled in the backend shouldn't be
29622984074SJames Feist                         // able to be set at the same time, so we don't need to
29722984074SJames Feist                         // check for the race condition of these two calls
29822984074SJames Feist                         if ((*updating))
29922984074SJames Feist                         {
30022984074SJames Feist                             asyncResp->res.jsonValue["Status"]["State"] =
30122984074SJames Feist                                 "Updating";
30222984074SJames Feist                         }
30322984074SJames Feist                     },
30422984074SJames Feist                     connectionName, path, "org.freedesktop.DBus.Properties",
30522984074SJames Feist                     "Get", "xyz.openbmc_project.State.Drive", "Rebuilding");
306a25aeccfSNikhil Potade             },
307a25aeccfSNikhil Potade             "xyz.openbmc_project.ObjectMapper",
308a25aeccfSNikhil Potade             "/xyz/openbmc_project/object_mapper",
309a25aeccfSNikhil Potade             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
310a25aeccfSNikhil Potade             "/xyz/openbmc_project/inventory", int32_t(0),
311a25aeccfSNikhil Potade             std::array<const char *, 1>{
312a25aeccfSNikhil Potade                 "xyz.openbmc_project.Inventory.Item.Drive"});
313a25aeccfSNikhil Potade     }
314a25aeccfSNikhil Potade };
315a25aeccfSNikhil Potade } // namespace redfish
316