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