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