xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision 729dae72826e58134ca4e49587427703ad0286db)
1*729dae72SJennifer Lee /*
2*729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation
3*729dae72SJennifer Lee //
4*729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License");
5*729dae72SJennifer Lee // you may not use this file except in compliance with the License.
6*729dae72SJennifer Lee // You may obtain a copy of the License at
7*729dae72SJennifer Lee //
8*729dae72SJennifer Lee //      http://www.apache.org/licenses/LICENSE-2.0
9*729dae72SJennifer Lee //
10*729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software
11*729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS,
12*729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*729dae72SJennifer Lee // See the License for the specific language governing permissions and
14*729dae72SJennifer Lee // limitations under the License.
15*729dae72SJennifer Lee */
16*729dae72SJennifer Lee #pragma once
17*729dae72SJennifer Lee 
18*729dae72SJennifer Lee #include "node.hpp"
19*729dae72SJennifer Lee #include <boost/container/flat_map.hpp>
20*729dae72SJennifer Lee 
21*729dae72SJennifer Lee namespace redfish {
22*729dae72SJennifer Lee 
23*729dae72SJennifer Lee class OnDemandSoftwareInventoryProvider {
24*729dae72SJennifer Lee  public:
25*729dae72SJennifer Lee   template <typename CallbackFunc>
26*729dae72SJennifer Lee   void get_all_software_inventory_data(CallbackFunc &&callback) {
27*729dae72SJennifer Lee     crow::connections::system_bus->async_method_call(
28*729dae72SJennifer Lee         [callback{std::move(callback)}](
29*729dae72SJennifer Lee             const boost::system::error_code error_code,
30*729dae72SJennifer Lee             const std::vector<std::pair<
31*729dae72SJennifer Lee                 std::string,
32*729dae72SJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
33*729dae72SJennifer Lee                 &subtree) {
34*729dae72SJennifer Lee 
35*729dae72SJennifer Lee           std::vector<boost::container::flat_map<std::string, std::string>>
36*729dae72SJennifer Lee               output;
37*729dae72SJennifer Lee 
38*729dae72SJennifer Lee           if (error_code) {
39*729dae72SJennifer Lee             // Something wrong on DBus, the error_code is not important at this
40*729dae72SJennifer Lee             // moment, just return success=false, and empty output. Since size
41*729dae72SJennifer Lee             // of vector may vary depending on information from Entity Manager,
42*729dae72SJennifer Lee             // and empty output could not be treated same way as error.
43*729dae72SJennifer Lee             callback(false, output);
44*729dae72SJennifer Lee             return;
45*729dae72SJennifer Lee           }
46*729dae72SJennifer Lee 
47*729dae72SJennifer Lee           for (auto &obj : subtree) {
48*729dae72SJennifer Lee             const std::vector<std::pair<std::string, std::vector<std::string>>>
49*729dae72SJennifer Lee                 &connectionNames = obj.second;
50*729dae72SJennifer Lee 
51*729dae72SJennifer Lee             const std::string connectionName = connectionNames[0].first;
52*729dae72SJennifer Lee 
53*729dae72SJennifer Lee             crow::connections::system_bus->async_method_call(
54*729dae72SJennifer Lee                 [&](const boost::system::error_code error_code,
55*729dae72SJennifer Lee                     const std::vector<std::pair<std::string, VariantType>>
56*729dae72SJennifer Lee                         &propertiesList) {
57*729dae72SJennifer Lee                   for (auto &property : propertiesList) {
58*729dae72SJennifer Lee                     boost::container::flat_map<std::string, std::string>
59*729dae72SJennifer Lee                         single_sw_item_properties;
60*729dae72SJennifer Lee                     single_sw_item_properties[property.first] =
61*729dae72SJennifer Lee                         *(mapbox::get_ptr<const std::string>(property.second));
62*729dae72SJennifer Lee                     output.emplace_back(single_sw_item_properties);
63*729dae72SJennifer Lee                   }
64*729dae72SJennifer Lee                 },
65*729dae72SJennifer Lee                 connectionName, obj.first, "org.freedesktop.DBus.Properties",
66*729dae72SJennifer Lee                 "GetAll", "xyz.openbmc_project.Software.Version");
67*729dae72SJennifer Lee             // Finally make a callback with usefull data
68*729dae72SJennifer Lee             callback(true, output);
69*729dae72SJennifer Lee           }
70*729dae72SJennifer Lee         },
71*729dae72SJennifer Lee         "xyz.openbmc_project.ObjectMapper",
72*729dae72SJennifer Lee         "/xyz/openbmc_project/object_mapper",
73*729dae72SJennifer Lee         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
74*729dae72SJennifer Lee         "/xyz/openbmc_project/software", int32_t(0),
75*729dae72SJennifer Lee         std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
76*729dae72SJennifer Lee   }
77*729dae72SJennifer Lee   /*
78*729dae72SJennifer Lee    * Function that retrieves all SoftwareInventory available through
79*729dae72SJennifer Lee    * Software.BMC.Updater.
80*729dae72SJennifer Lee    * @param callback a function that shall be called to convert Dbus output into
81*729dae72SJennifer Lee    * JSON.
82*729dae72SJennifer Lee    */
83*729dae72SJennifer Lee   template <typename CallbackFunc>
84*729dae72SJennifer Lee   void get_software_inventory_list(CallbackFunc &&callback) {
85*729dae72SJennifer Lee     get_all_software_inventory_data(
86*729dae72SJennifer Lee         [callback](
87*729dae72SJennifer Lee             const bool &success,
88*729dae72SJennifer Lee             const std::vector<
89*729dae72SJennifer Lee                 boost::container::flat_map<std::string, std::string>> &output) {
90*729dae72SJennifer Lee           std::vector<std::string> sw_inv_list;
91*729dae72SJennifer Lee           for (auto &i : output) {
92*729dae72SJennifer Lee             boost::container::flat_map<std::string, std::string>::const_iterator
93*729dae72SJennifer Lee                 p = i.find("Purpose");
94*729dae72SJennifer Lee             if ((p != i.end())) {
95*729dae72SJennifer Lee               const std::string &sw_inv_purpose =
96*729dae72SJennifer Lee                   boost::get<std::string>(p->second);
97*729dae72SJennifer Lee               std::size_t last_pos = sw_inv_purpose.rfind(".");
98*729dae72SJennifer Lee               if (last_pos != std::string::npos) {
99*729dae72SJennifer Lee                 // and put it into output vector.
100*729dae72SJennifer Lee                 sw_inv_list.emplace_back(sw_inv_purpose.substr(last_pos + 1));
101*729dae72SJennifer Lee               }
102*729dae72SJennifer Lee             }
103*729dae72SJennifer Lee           }
104*729dae72SJennifer Lee           callback(true, sw_inv_list);
105*729dae72SJennifer Lee         });
106*729dae72SJennifer Lee   };
107*729dae72SJennifer Lee 
108*729dae72SJennifer Lee   template <typename CallbackFunc>
109*729dae72SJennifer Lee   void get_software_inventory_data(const std::string &res_name,
110*729dae72SJennifer Lee                                    CallbackFunc &&callback) {
111*729dae72SJennifer Lee     get_all_software_inventory_data(
112*729dae72SJennifer Lee         [res_name, callback](
113*729dae72SJennifer Lee             const bool &success,
114*729dae72SJennifer Lee             const std::vector<
115*729dae72SJennifer Lee                 boost::container::flat_map<std::string, std::string>> &output) {
116*729dae72SJennifer Lee           for (auto &i : output) {
117*729dae72SJennifer Lee             boost::container::flat_map<std::string, std::string>::const_iterator
118*729dae72SJennifer Lee                 p = i.find("Purpose");
119*729dae72SJennifer Lee             // Find the one with Purpose matching res_name
120*729dae72SJennifer Lee             if ((p != i.end()) &&
121*729dae72SJennifer Lee                 boost::ends_with(boost::get<std::string>(p->second),
122*729dae72SJennifer Lee                                  "." + res_name)) {
123*729dae72SJennifer Lee               callback(true, i);
124*729dae72SJennifer Lee             }
125*729dae72SJennifer Lee           }
126*729dae72SJennifer Lee         });
127*729dae72SJennifer Lee   }
128*729dae72SJennifer Lee };
129*729dae72SJennifer Lee 
130*729dae72SJennifer Lee class UpdateService : public Node {
131*729dae72SJennifer Lee  public:
132*729dae72SJennifer Lee   UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
133*729dae72SJennifer Lee     Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
134*729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService";
135*729dae72SJennifer Lee     Node::json["@odata.context"] =
136*729dae72SJennifer Lee         "/redfish/v1/$metadata#UpdateService.UpdateService";
137*729dae72SJennifer Lee     Node::json["Id"] = "UpdateService";
138*729dae72SJennifer Lee     Node::json["Description"] = "Service for Software Update";
139*729dae72SJennifer Lee     Node::json["Name"] = "Update Service";
140*729dae72SJennifer Lee     Node::json["ServiceEnabled"] = true;  // UpdateService cannot be disabled
141*729dae72SJennifer Lee     Node::json["SoftwareInventory"] = {
142*729dae72SJennifer Lee         {"@odata.id", "/redfish/v1/UpdateService/SoftwareInventory"}};
143*729dae72SJennifer Lee 
144*729dae72SJennifer Lee     entityPrivileges = {
145*729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
146*729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
147*729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
148*729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
149*729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
150*729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
151*729dae72SJennifer Lee   }
152*729dae72SJennifer Lee 
153*729dae72SJennifer Lee  private:
154*729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
155*729dae72SJennifer Lee              const std::vector<std::string> &params) override {
156*729dae72SJennifer Lee     res.json_value = Node::json;
157*729dae72SJennifer Lee     res.end();
158*729dae72SJennifer Lee   }
159*729dae72SJennifer Lee };
160*729dae72SJennifer Lee 
161*729dae72SJennifer Lee class SoftwareInventoryCollection : public Node {
162*729dae72SJennifer Lee  public:
163*729dae72SJennifer Lee   /*
164*729dae72SJennifer Lee    * Default Constructor
165*729dae72SJennifer Lee    */
166*729dae72SJennifer Lee   template <typename CrowApp>
167*729dae72SJennifer Lee   SoftwareInventoryCollection(CrowApp &app)
168*729dae72SJennifer Lee       : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/") {
169*729dae72SJennifer Lee     Node::json["@odata.type"] =
170*729dae72SJennifer Lee         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
171*729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory";
172*729dae72SJennifer Lee     Node::json["@odata.context"] =
173*729dae72SJennifer Lee         "/redfish/v1/"
174*729dae72SJennifer Lee         "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
175*729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory Collection";
176*729dae72SJennifer Lee 
177*729dae72SJennifer Lee     entityPrivileges = {
178*729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
179*729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
180*729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
181*729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
182*729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
183*729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
184*729dae72SJennifer Lee   }
185*729dae72SJennifer Lee 
186*729dae72SJennifer Lee  private:
187*729dae72SJennifer Lee   /**
188*729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
189*729dae72SJennifer Lee    */
190*729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
191*729dae72SJennifer Lee              const std::vector<std::string> &params) override {
192*729dae72SJennifer Lee     res.json_value = Node::json;
193*729dae72SJennifer Lee     // Get sw inventory list, and call the below callback for JSON preparation
194*729dae72SJennifer Lee     software_inventory_provider.get_software_inventory_list(
195*729dae72SJennifer Lee         [&](const bool &success, const std::vector<std::string> &output) {
196*729dae72SJennifer Lee 
197*729dae72SJennifer Lee           if (success) {
198*729dae72SJennifer Lee             // ... prepare json array with appropriate @odata.id links
199*729dae72SJennifer Lee             nlohmann::json sw_inventory_array = nlohmann::json::array();
200*729dae72SJennifer Lee             for (const std::string &sw_item : output) {
201*729dae72SJennifer Lee               sw_inventory_array.push_back(
202*729dae72SJennifer Lee                   {{"@odata.id",
203*729dae72SJennifer Lee                     "/redfish/v1/UpdateService/SoftwareInventory/" + sw_item}});
204*729dae72SJennifer Lee             }
205*729dae72SJennifer Lee             // Then attach members, count size and return
206*729dae72SJennifer Lee 
207*729dae72SJennifer Lee             Node::json["Members"] = sw_inventory_array;
208*729dae72SJennifer Lee             Node::json["Members@odata.count"] = sw_inventory_array.size();
209*729dae72SJennifer Lee             res.json_value = Node::json;
210*729dae72SJennifer Lee           } else {
211*729dae72SJennifer Lee             // ... otherwise, return INTERNALL ERROR
212*729dae72SJennifer Lee             res.result(boost::beast::http::status::internal_server_error);
213*729dae72SJennifer Lee           }
214*729dae72SJennifer Lee           res.end();
215*729dae72SJennifer Lee         });
216*729dae72SJennifer Lee     res.end();
217*729dae72SJennifer Lee   }
218*729dae72SJennifer Lee   OnDemandSoftwareInventoryProvider software_inventory_provider;
219*729dae72SJennifer Lee };
220*729dae72SJennifer Lee /**
221*729dae72SJennifer Lee  * Chassis override class for delivering Chassis Schema
222*729dae72SJennifer Lee  */
223*729dae72SJennifer Lee class SoftwareInventory : public Node {
224*729dae72SJennifer Lee  public:
225*729dae72SJennifer Lee   /*
226*729dae72SJennifer Lee    * Default Constructor
227*729dae72SJennifer Lee    */
228*729dae72SJennifer Lee   template <typename CrowApp>
229*729dae72SJennifer Lee   SoftwareInventory(CrowApp &app)
230*729dae72SJennifer Lee       : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/<str>/",
231*729dae72SJennifer Lee              std::string()) {
232*729dae72SJennifer Lee     Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
233*729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory";
234*729dae72SJennifer Lee     Node::json["@odata.context"] =
235*729dae72SJennifer Lee         "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
236*729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory";
237*729dae72SJennifer Lee     Node::json["Status"] = "OK";  // TODO
238*729dae72SJennifer Lee     Node::json["Updateable"] = "No";
239*729dae72SJennifer Lee 
240*729dae72SJennifer Lee     entityPrivileges = {
241*729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
242*729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
243*729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
244*729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
245*729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
246*729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
247*729dae72SJennifer Lee   }
248*729dae72SJennifer Lee 
249*729dae72SJennifer Lee  private:
250*729dae72SJennifer Lee   /**
251*729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
252*729dae72SJennifer Lee    */
253*729dae72SJennifer Lee   void doGet(crow::response &res, const crow::request &req,
254*729dae72SJennifer Lee              const std::vector<std::string> &params) override {
255*729dae72SJennifer Lee     if (params.size() != 1) {
256*729dae72SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
257*729dae72SJennifer Lee       res.end();
258*729dae72SJennifer Lee       return;
259*729dae72SJennifer Lee     }
260*729dae72SJennifer Lee     const std::string &sw_id = params[0];
261*729dae72SJennifer Lee     software_inventory_provider.get_software_inventory_data(
262*729dae72SJennifer Lee         sw_id, [&, id{std::string(sw_id)} ](
263*729dae72SJennifer Lee                    const bool &success,
264*729dae72SJennifer Lee                    const boost::container::flat_map<std::string, std::string>
265*729dae72SJennifer Lee                        &output) {
266*729dae72SJennifer Lee           res.json_value = Node::json;
267*729dae72SJennifer Lee           // If success...
268*729dae72SJennifer Lee           if (success) {
269*729dae72SJennifer Lee             // prepare all the schema required fields.
270*729dae72SJennifer Lee             res.json_value["@odata.id"] =
271*729dae72SJennifer Lee                 "/redfish/v1/UpdateService/SoftwareInventory/" + id;
272*729dae72SJennifer Lee             // also the one from dbus
273*729dae72SJennifer Lee             boost::container::flat_map<std::string, std::string>::const_iterator
274*729dae72SJennifer Lee                 it = output.find("Version");
275*729dae72SJennifer Lee             res.json_value["Version"] = boost::get<std::string>(it->second);
276*729dae72SJennifer Lee 
277*729dae72SJennifer Lee             res.json_value["Id"] = id;
278*729dae72SJennifer Lee             // prepare respond, and send
279*729dae72SJennifer Lee           } else {
280*729dae72SJennifer Lee             res.result(boost::beast::http::status::not_found);
281*729dae72SJennifer Lee           }
282*729dae72SJennifer Lee           res.end();
283*729dae72SJennifer Lee         });
284*729dae72SJennifer Lee   }
285*729dae72SJennifer Lee 
286*729dae72SJennifer Lee   OnDemandSoftwareInventoryProvider software_inventory_provider;
287*729dae72SJennifer Lee };
288*729dae72SJennifer Lee 
289*729dae72SJennifer Lee }  // namespace redfish
290