xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision 6c4eb9de85ae4d59af7b15754e96a1652915ad15)
1729dae72SJennifer Lee /*
2729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation
3729dae72SJennifer Lee //
4729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License");
5729dae72SJennifer Lee // you may not use this file except in compliance with the License.
6729dae72SJennifer Lee // You may obtain a copy of the License at
7729dae72SJennifer Lee //
8729dae72SJennifer Lee //      http://www.apache.org/licenses/LICENSE-2.0
9729dae72SJennifer Lee //
10729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software
11729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS,
12729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13729dae72SJennifer Lee // See the License for the specific language governing permissions and
14729dae72SJennifer Lee // limitations under the License.
15729dae72SJennifer Lee */
16729dae72SJennifer Lee #pragma once
17729dae72SJennifer Lee 
18729dae72SJennifer Lee #include "node.hpp"
19729dae72SJennifer Lee #include <boost/container/flat_map.hpp>
20729dae72SJennifer Lee 
21729dae72SJennifer Lee namespace redfish {
22729dae72SJennifer Lee 
23729dae72SJennifer Lee class OnDemandSoftwareInventoryProvider {
24729dae72SJennifer Lee  public:
25729dae72SJennifer Lee   template <typename CallbackFunc>
26*6c4eb9deSJennifer Lee   void get_all_software_inventory_object(CallbackFunc &&callback) {
27729dae72SJennifer Lee     crow::connections::system_bus->async_method_call(
28729dae72SJennifer Lee         [callback{std::move(callback)}](
29729dae72SJennifer Lee             const boost::system::error_code error_code,
30729dae72SJennifer Lee             const std::vector<std::pair<
31729dae72SJennifer Lee                 std::string,
32729dae72SJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
33729dae72SJennifer Lee                 &subtree) {
34*6c4eb9deSJennifer Lee           CROW_LOG_DEBUG << "get all software inventory object callback...";
35729dae72SJennifer Lee           if (error_code) {
36729dae72SJennifer Lee             // Something wrong on DBus, the error_code is not important at this
37729dae72SJennifer Lee             // moment, just return success=false, and empty output. Since size
38729dae72SJennifer Lee             // of vector may vary depending on information from Entity Manager,
39729dae72SJennifer Lee             // and empty output could not be treated same way as error.
40*6c4eb9deSJennifer Lee             callback(false, subtree);
41729dae72SJennifer Lee             return;
42729dae72SJennifer Lee           }
43729dae72SJennifer Lee 
44*6c4eb9deSJennifer Lee           if (subtree.empty()) {
45*6c4eb9deSJennifer Lee             CROW_LOG_DEBUG << "subtree empty";
46*6c4eb9deSJennifer Lee             callback(false, subtree);
47*6c4eb9deSJennifer Lee           } else {
48*6c4eb9deSJennifer Lee             CROW_LOG_DEBUG << "subtree has something";
49*6c4eb9deSJennifer Lee             callback(true, subtree);
50729dae72SJennifer Lee           }
51729dae72SJennifer Lee         },
52729dae72SJennifer Lee         "xyz.openbmc_project.ObjectMapper",
53729dae72SJennifer Lee         "/xyz/openbmc_project/object_mapper",
54*6c4eb9deSJennifer Lee         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
55*6c4eb9deSJennifer Lee         "/xyz/openbmc_project/software", int32_t(1),
56729dae72SJennifer Lee         std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
57729dae72SJennifer Lee   }
58729dae72SJennifer Lee };
59729dae72SJennifer Lee 
60729dae72SJennifer Lee class UpdateService : public Node {
61729dae72SJennifer Lee  public:
62729dae72SJennifer Lee   UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
63729dae72SJennifer Lee     Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
64729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService";
65729dae72SJennifer Lee     Node::json["@odata.context"] =
66729dae72SJennifer Lee         "/redfish/v1/$metadata#UpdateService.UpdateService";
67729dae72SJennifer Lee     Node::json["Id"] = "UpdateService";
68729dae72SJennifer Lee     Node::json["Description"] = "Service for Software Update";
69729dae72SJennifer Lee     Node::json["Name"] = "Update Service";
70729dae72SJennifer Lee     Node::json["ServiceEnabled"] = true;  // UpdateService cannot be disabled
71*6c4eb9deSJennifer Lee     Node::json["FirmwareInventory"] = {
72*6c4eb9deSJennifer Lee         {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
73729dae72SJennifer Lee 
74729dae72SJennifer Lee     entityPrivileges = {
75729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
76729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
77729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
78729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
79729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
80729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
81729dae72SJennifer Lee   }
82729dae72SJennifer Lee 
83729dae72SJennifer Lee  private:
84729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
85729dae72SJennifer Lee              const std::vector<std::string> &params) override {
86729dae72SJennifer Lee     res.json_value = Node::json;
87729dae72SJennifer Lee     res.end();
88729dae72SJennifer Lee   }
89729dae72SJennifer Lee };
90729dae72SJennifer Lee 
91729dae72SJennifer Lee class SoftwareInventoryCollection : public Node {
92729dae72SJennifer Lee  public:
93729dae72SJennifer Lee   /*
94729dae72SJennifer Lee    * Default Constructor
95729dae72SJennifer Lee    */
96729dae72SJennifer Lee   template <typename CrowApp>
97729dae72SJennifer Lee   SoftwareInventoryCollection(CrowApp &app)
98*6c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") {
99729dae72SJennifer Lee     Node::json["@odata.type"] =
100729dae72SJennifer Lee         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
101*6c4eb9deSJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
102729dae72SJennifer Lee     Node::json["@odata.context"] =
103729dae72SJennifer Lee         "/redfish/v1/"
104729dae72SJennifer Lee         "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
105729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory Collection";
106729dae72SJennifer Lee 
107729dae72SJennifer Lee     entityPrivileges = {
108729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
109729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
110729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
111729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
112729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
113729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
114729dae72SJennifer Lee   }
115729dae72SJennifer Lee 
116729dae72SJennifer Lee  private:
117729dae72SJennifer Lee   /**
118729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
119729dae72SJennifer Lee    */
120729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
121729dae72SJennifer Lee              const std::vector<std::string> &params) override {
122729dae72SJennifer Lee     res.json_value = Node::json;
123*6c4eb9deSJennifer Lee     software_inventory_provider.get_all_software_inventory_object(
124*6c4eb9deSJennifer Lee         [&](const bool &success,
125*6c4eb9deSJennifer Lee             const std::vector<std::pair<
126*6c4eb9deSJennifer Lee                 std::string,
127*6c4eb9deSJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
128*6c4eb9deSJennifer Lee                 &subtree) {
129*6c4eb9deSJennifer Lee           if (!success) {
130729dae72SJennifer Lee             res.result(boost::beast::http::status::internal_server_error);
131*6c4eb9deSJennifer Lee             res.end();
132*6c4eb9deSJennifer Lee             return;
133729dae72SJennifer Lee           }
134*6c4eb9deSJennifer Lee 
135*6c4eb9deSJennifer Lee           if (subtree.empty()) {
136*6c4eb9deSJennifer Lee             CROW_LOG_DEBUG << "subtree empty!!";
137729dae72SJennifer Lee             res.end();
138*6c4eb9deSJennifer Lee             return;
139*6c4eb9deSJennifer Lee           }
140*6c4eb9deSJennifer Lee 
141*6c4eb9deSJennifer Lee           res.json_value["Members"] = nlohmann::json::array();
142*6c4eb9deSJennifer Lee 
143*6c4eb9deSJennifer Lee           for (auto &obj : subtree) {
144*6c4eb9deSJennifer Lee             const std::vector<std::pair<std::string, std::vector<std::string>>>
145*6c4eb9deSJennifer Lee                 &connections = obj.second;
146*6c4eb9deSJennifer Lee 
147*6c4eb9deSJennifer Lee             for (auto &conn : connections) {
148*6c4eb9deSJennifer Lee               const std::string connectionName = conn.first;
149*6c4eb9deSJennifer Lee               CROW_LOG_DEBUG << "connectionName = " << connectionName;
150*6c4eb9deSJennifer Lee               CROW_LOG_DEBUG << "obj.first = " << obj.first;
151*6c4eb9deSJennifer Lee 
152*6c4eb9deSJennifer Lee               crow::connections::system_bus->async_method_call(
153*6c4eb9deSJennifer Lee                   [&](const boost::system::error_code error_code,
154*6c4eb9deSJennifer Lee                       const boost::container::flat_map<std::string, VariantType>
155*6c4eb9deSJennifer Lee                           &propertiesList) {
156*6c4eb9deSJennifer Lee                     CROW_LOG_DEBUG << "safe returned in lambda function";
157*6c4eb9deSJennifer Lee                     if (error_code) {
158*6c4eb9deSJennifer Lee                       res.result(
159*6c4eb9deSJennifer Lee                           boost::beast::http::status::internal_server_error);
160*6c4eb9deSJennifer Lee                       res.end();
161*6c4eb9deSJennifer Lee                       return;
162*6c4eb9deSJennifer Lee                     }
163*6c4eb9deSJennifer Lee                     boost::container::flat_map<std::string,
164*6c4eb9deSJennifer Lee                                                VariantType>::const_iterator it =
165*6c4eb9deSJennifer Lee                         propertiesList.find("Purpose");
166*6c4eb9deSJennifer Lee                     const std::string &sw_inv_purpose =
167*6c4eb9deSJennifer Lee                         *(mapbox::get_ptr<const std::string>(it->second));
168*6c4eb9deSJennifer Lee                     std::size_t last_pos = sw_inv_purpose.rfind(".");
169*6c4eb9deSJennifer Lee                     if (last_pos != std::string::npos) {
170*6c4eb9deSJennifer Lee                       res.json_value["Members"].push_back(
171*6c4eb9deSJennifer Lee                           {{"@odata.id",
172*6c4eb9deSJennifer Lee                             "/redfish/v1/UpdateService/FirmwareInventory/" +
173*6c4eb9deSJennifer Lee                                 sw_inv_purpose.substr(last_pos + 1)}});
174*6c4eb9deSJennifer Lee                       res.json_value["Members@odata.count"] =
175*6c4eb9deSJennifer Lee                           res.json_value["Members"].size();
176*6c4eb9deSJennifer Lee                       res.end();
177*6c4eb9deSJennifer Lee                     }
178*6c4eb9deSJennifer Lee 
179*6c4eb9deSJennifer Lee                   },
180*6c4eb9deSJennifer Lee                   connectionName, obj.first, "org.freedesktop.DBus.Properties",
181*6c4eb9deSJennifer Lee                   "GetAll", "xyz.openbmc_project.Software.Version");
182*6c4eb9deSJennifer Lee             }
183*6c4eb9deSJennifer Lee           }
184729dae72SJennifer Lee         });
185729dae72SJennifer Lee   }
186729dae72SJennifer Lee   OnDemandSoftwareInventoryProvider software_inventory_provider;
187729dae72SJennifer Lee };
188729dae72SJennifer Lee /**
189729dae72SJennifer Lee  * Chassis override class for delivering Chassis Schema
190729dae72SJennifer Lee  */
191729dae72SJennifer Lee class SoftwareInventory : public Node {
192729dae72SJennifer Lee  public:
193729dae72SJennifer Lee   /*
194729dae72SJennifer Lee    * Default Constructor
195729dae72SJennifer Lee    */
196729dae72SJennifer Lee   template <typename CrowApp>
197729dae72SJennifer Lee   SoftwareInventory(CrowApp &app)
198*6c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
199729dae72SJennifer Lee              std::string()) {
200729dae72SJennifer Lee     Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
201729dae72SJennifer Lee     Node::json["@odata.context"] =
202729dae72SJennifer Lee         "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
203729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory";
204729dae72SJennifer Lee     Node::json["Status"] = "OK";  // TODO
205*6c4eb9deSJennifer Lee     Node::json["Updateable"] = false;
206729dae72SJennifer Lee 
207729dae72SJennifer Lee     entityPrivileges = {
208729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
209729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
210729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
211729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
212729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
213729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
214729dae72SJennifer Lee   }
215729dae72SJennifer Lee 
216729dae72SJennifer Lee  private:
217729dae72SJennifer Lee   /**
218729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
219729dae72SJennifer Lee    */
220729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
221729dae72SJennifer Lee              const std::vector<std::string> &params) override {
222*6c4eb9deSJennifer Lee     res.json_value = Node::json;
223*6c4eb9deSJennifer Lee 
224729dae72SJennifer Lee     if (params.size() != 1) {
225729dae72SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
226729dae72SJennifer Lee       res.end();
227729dae72SJennifer Lee       return;
228729dae72SJennifer Lee     }
229729dae72SJennifer Lee 
230*6c4eb9deSJennifer Lee     const std::string &sw_id = params[0];
231*6c4eb9deSJennifer Lee     res.json_value["@odata.id"] =
232*6c4eb9deSJennifer Lee         "/redfish/v1/UpdateService/FirmwareInventory/" + sw_id;
233*6c4eb9deSJennifer Lee     software_inventory_provider.get_all_software_inventory_object(
234*6c4eb9deSJennifer Lee         [&, id{std::string(sw_id)} ](
235*6c4eb9deSJennifer Lee             const bool &success,
236*6c4eb9deSJennifer Lee             const std::vector<std::pair<
237*6c4eb9deSJennifer Lee                 std::string,
238*6c4eb9deSJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
239*6c4eb9deSJennifer Lee                 &subtree) {
240*6c4eb9deSJennifer Lee           CROW_LOG_DEBUG << "doGet callback...";
241*6c4eb9deSJennifer Lee           if (!success) {
242*6c4eb9deSJennifer Lee             res.result(boost::beast::http::status::internal_server_error);
243729dae72SJennifer Lee             res.end();
244*6c4eb9deSJennifer Lee             return;
245*6c4eb9deSJennifer Lee           }
246*6c4eb9deSJennifer Lee 
247*6c4eb9deSJennifer Lee           if (subtree.empty()) {
248*6c4eb9deSJennifer Lee             CROW_LOG_DEBUG << "subtree empty!!";
249*6c4eb9deSJennifer Lee             res.end();
250*6c4eb9deSJennifer Lee             return;
251*6c4eb9deSJennifer Lee           }
252*6c4eb9deSJennifer Lee 
253*6c4eb9deSJennifer Lee           for (auto &obj : subtree) {
254*6c4eb9deSJennifer Lee             const std::vector<std::pair<std::string, std::vector<std::string>>>
255*6c4eb9deSJennifer Lee                 &connections = obj.second;
256*6c4eb9deSJennifer Lee 
257*6c4eb9deSJennifer Lee             for (auto &conn : connections) {
258*6c4eb9deSJennifer Lee               const std::string connectionName = conn.first;
259*6c4eb9deSJennifer Lee               CROW_LOG_DEBUG << "connectionName = " << connectionName;
260*6c4eb9deSJennifer Lee               CROW_LOG_DEBUG << "obj.first = " << obj.first;
261*6c4eb9deSJennifer Lee 
262*6c4eb9deSJennifer Lee               crow::connections::system_bus->async_method_call(
263*6c4eb9deSJennifer Lee                   [&, id{std::string(id)} ](
264*6c4eb9deSJennifer Lee                       const boost::system::error_code error_code,
265*6c4eb9deSJennifer Lee                       const boost::container::flat_map<std::string, VariantType>
266*6c4eb9deSJennifer Lee                           &propertiesList) {
267*6c4eb9deSJennifer Lee                     if (error_code) {
268*6c4eb9deSJennifer Lee                       res.result(
269*6c4eb9deSJennifer Lee                           boost::beast::http::status::internal_server_error);
270*6c4eb9deSJennifer Lee                       res.end();
271*6c4eb9deSJennifer Lee                       return;
272*6c4eb9deSJennifer Lee                     }
273*6c4eb9deSJennifer Lee                     boost::container::flat_map<std::string,
274*6c4eb9deSJennifer Lee                                                VariantType>::const_iterator it =
275*6c4eb9deSJennifer Lee                         propertiesList.find("Purpose");
276*6c4eb9deSJennifer Lee                     if (it == propertiesList.end()) {
277*6c4eb9deSJennifer Lee                       CROW_LOG_DEBUG << "Can't find property \"Purpose\"!";
278*6c4eb9deSJennifer Lee                       return;
279*6c4eb9deSJennifer Lee                     }
280*6c4eb9deSJennifer Lee                     const std::string &sw_inv_purpose =
281*6c4eb9deSJennifer Lee                         *(mapbox::get_ptr<const std::string>(it->second));
282*6c4eb9deSJennifer Lee                     CROW_LOG_DEBUG << "sw_inv_purpose = " << sw_inv_purpose;
283*6c4eb9deSJennifer Lee                     if (boost::ends_with(sw_inv_purpose, "." + id)) {
284*6c4eb9deSJennifer Lee                       it = propertiesList.find("Version");
285*6c4eb9deSJennifer Lee                       if (it == propertiesList.end()) {
286*6c4eb9deSJennifer Lee                         CROW_LOG_DEBUG << "Can't find property \"Version\"!";
287*6c4eb9deSJennifer Lee                         return;
288*6c4eb9deSJennifer Lee                       }
289*6c4eb9deSJennifer Lee                       res.json_value["Version"] =
290*6c4eb9deSJennifer Lee                           *(mapbox::get_ptr<const std::string>(it->second));
291*6c4eb9deSJennifer Lee                       res.json_value["Id"] = id;
292*6c4eb9deSJennifer Lee                       res.end();
293*6c4eb9deSJennifer Lee                     }
294*6c4eb9deSJennifer Lee 
295*6c4eb9deSJennifer Lee                   },
296*6c4eb9deSJennifer Lee                   connectionName, obj.first, "org.freedesktop.DBus.Properties",
297*6c4eb9deSJennifer Lee                   "GetAll", "xyz.openbmc_project.Software.Version");
298*6c4eb9deSJennifer Lee             }
299*6c4eb9deSJennifer Lee           }
300729dae72SJennifer Lee         });
301729dae72SJennifer Lee   }
302729dae72SJennifer Lee 
303729dae72SJennifer Lee   OnDemandSoftwareInventoryProvider software_inventory_provider;
304729dae72SJennifer Lee };
305729dae72SJennifer Lee 
306729dae72SJennifer Lee }  // namespace redfish
307