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