xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision acb7cfb4b571bd2045b1d269625ba054806a466d)
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 {
22*acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
23729dae72SJennifer Lee 
24729dae72SJennifer Lee class OnDemandSoftwareInventoryProvider {
25729dae72SJennifer Lee  public:
26729dae72SJennifer Lee   template <typename CallbackFunc>
27*acb7cfb4SJennifer Lee   void getAllSoftwareInventoryObject(CallbackFunc &&callback) {
2855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
29729dae72SJennifer Lee         [callback{std::move(callback)}](
30729dae72SJennifer Lee             const boost::system::error_code error_code,
31729dae72SJennifer Lee             const std::vector<std::pair<
32729dae72SJennifer Lee                 std::string,
33729dae72SJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
34729dae72SJennifer Lee                 &subtree) {
3555c7b7a2SEd Tanous           BMCWEB_LOG_DEBUG << "get all software inventory object callback...";
36729dae72SJennifer Lee           if (error_code) {
37729dae72SJennifer Lee             // Something wrong on DBus, the error_code is not important at this
38729dae72SJennifer Lee             // moment, just return success=false, and empty output. Since size
39729dae72SJennifer Lee             // of vector may vary depending on information from Entity Manager,
40729dae72SJennifer Lee             // and empty output could not be treated same way as error.
416c4eb9deSJennifer Lee             callback(false, subtree);
42729dae72SJennifer Lee             return;
43729dae72SJennifer Lee           }
44729dae72SJennifer Lee 
456c4eb9deSJennifer Lee           if (subtree.empty()) {
4655c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "subtree empty";
476c4eb9deSJennifer Lee             callback(false, subtree);
486c4eb9deSJennifer Lee           } else {
4955c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "subtree has something";
506c4eb9deSJennifer Lee             callback(true, subtree);
51729dae72SJennifer Lee           }
52729dae72SJennifer Lee         },
53729dae72SJennifer Lee         "xyz.openbmc_project.ObjectMapper",
54729dae72SJennifer Lee         "/xyz/openbmc_project/object_mapper",
556c4eb9deSJennifer Lee         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
566c4eb9deSJennifer Lee         "/xyz/openbmc_project/software", int32_t(1),
57*acb7cfb4SJennifer Lee         std::array<const char *, 1>{"xyz.openbmc_project.Software.Activation"});
58729dae72SJennifer Lee   }
59729dae72SJennifer Lee };
60729dae72SJennifer Lee 
61729dae72SJennifer Lee class UpdateService : public Node {
62729dae72SJennifer Lee  public:
63729dae72SJennifer Lee   UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
64729dae72SJennifer Lee     Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
65729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService";
66729dae72SJennifer Lee     Node::json["@odata.context"] =
67729dae72SJennifer Lee         "/redfish/v1/$metadata#UpdateService.UpdateService";
68729dae72SJennifer Lee     Node::json["Id"] = "UpdateService";
69729dae72SJennifer Lee     Node::json["Description"] = "Service for Software Update";
70729dae72SJennifer Lee     Node::json["Name"] = "Update Service";
71*acb7cfb4SJennifer Lee     Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
72729dae72SJennifer Lee     Node::json["ServiceEnabled"] = true;  // UpdateService cannot be disabled
736c4eb9deSJennifer Lee     Node::json["FirmwareInventory"] = {
746c4eb9deSJennifer Lee         {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
75729dae72SJennifer Lee 
76729dae72SJennifer Lee     entityPrivileges = {
77729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
78729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
79729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
80729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
81729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
82729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
83729dae72SJennifer Lee   }
84729dae72SJennifer Lee 
85729dae72SJennifer Lee  private:
8655c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
87729dae72SJennifer Lee              const std::vector<std::string> &params) override {
8855c7b7a2SEd Tanous     res.jsonValue = Node::json;
89729dae72SJennifer Lee     res.end();
90729dae72SJennifer Lee   }
91*acb7cfb4SJennifer Lee   static void activateImage(const std::string &obj_path) {
92*acb7cfb4SJennifer Lee     crow::connections::systemBus->async_method_call(
93*acb7cfb4SJennifer Lee         [obj_path](const boost::system::error_code error_code) {
94*acb7cfb4SJennifer Lee           if (error_code) {
95*acb7cfb4SJennifer Lee             BMCWEB_LOG_DEBUG << "error_code = " << error_code;
96*acb7cfb4SJennifer Lee             BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
97*acb7cfb4SJennifer Lee           }
98*acb7cfb4SJennifer Lee         },
99*acb7cfb4SJennifer Lee         "xyz.openbmc_project.Software.BMC.Updater", obj_path,
100*acb7cfb4SJennifer Lee         "org.freedesktop.DBus.Properties", "Set",
101*acb7cfb4SJennifer Lee         "xyz.openbmc_project.Software.Activation", "RequestedActivation",
102*acb7cfb4SJennifer Lee         sdbusplus::message::variant<std::string>(
103*acb7cfb4SJennifer Lee             "xyz.openbmc_project.Software.Activation.RequestedActivations."
104*acb7cfb4SJennifer Lee             "Active"));
105*acb7cfb4SJennifer Lee   }
106*acb7cfb4SJennifer Lee   void doPost(crow::Response &res, const crow::Request &req,
107*acb7cfb4SJennifer Lee               const std::vector<std::string> &params) override {
108*acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "doPost...";
109*acb7cfb4SJennifer Lee 
110*acb7cfb4SJennifer Lee     // Only allow one FW update at a time
111*acb7cfb4SJennifer Lee     if (fwUpdateMatcher != nullptr) {
112*acb7cfb4SJennifer Lee       res.addHeader("Retry-After", "30");
113*acb7cfb4SJennifer Lee       res.result(boost::beast::http::status::service_unavailable);
114*acb7cfb4SJennifer Lee       res.jsonValue = messages::serviceTemporarilyUnavailable("3");
115*acb7cfb4SJennifer Lee       res.end();
116*acb7cfb4SJennifer Lee       return;
117*acb7cfb4SJennifer Lee     }
118*acb7cfb4SJennifer Lee     // Make this const static so it survives outside this method
119*acb7cfb4SJennifer Lee     static boost::asio::deadline_timer timeout(*req.ioService,
120*acb7cfb4SJennifer Lee                                                boost::posix_time::seconds(5));
121*acb7cfb4SJennifer Lee 
122*acb7cfb4SJennifer Lee     timeout.expires_from_now(boost::posix_time::seconds(5));
123*acb7cfb4SJennifer Lee 
124*acb7cfb4SJennifer Lee     timeout.async_wait([&res](const boost::system::error_code &ec) {
125*acb7cfb4SJennifer Lee       fwUpdateMatcher = nullptr;
126*acb7cfb4SJennifer Lee       if (ec == boost::asio::error::operation_aborted) {
127*acb7cfb4SJennifer Lee         // expected, we were canceled before the timer completed.
128*acb7cfb4SJennifer Lee         return;
129*acb7cfb4SJennifer Lee       }
130*acb7cfb4SJennifer Lee       BMCWEB_LOG_ERROR << "Timed out waiting for firmware object being created";
131*acb7cfb4SJennifer Lee       BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
132*acb7cfb4SJennifer Lee       if (ec) {
133*acb7cfb4SJennifer Lee         BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
134*acb7cfb4SJennifer Lee         return;
135*acb7cfb4SJennifer Lee       }
136*acb7cfb4SJennifer Lee 
137*acb7cfb4SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
138*acb7cfb4SJennifer Lee       res.jsonValue = redfish::messages::internalError();
139*acb7cfb4SJennifer Lee       res.end();
140*acb7cfb4SJennifer Lee     });
141*acb7cfb4SJennifer Lee 
142*acb7cfb4SJennifer Lee     auto callback = [&res](sdbusplus::message::message &m) {
143*acb7cfb4SJennifer Lee       BMCWEB_LOG_DEBUG << "Match fired";
144*acb7cfb4SJennifer Lee       bool flag = false;
145*acb7cfb4SJennifer Lee 
146*acb7cfb4SJennifer Lee       if (m.is_method_error()) {
147*acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "Dbus method error!!!";
148*acb7cfb4SJennifer Lee         res.end();
149*acb7cfb4SJennifer Lee         return;
150*acb7cfb4SJennifer Lee       }
151*acb7cfb4SJennifer Lee       std::vector<std::pair<
152*acb7cfb4SJennifer Lee           std::string,
153*acb7cfb4SJennifer Lee           std::vector<std::pair<std::string,
154*acb7cfb4SJennifer Lee                                 sdbusplus::message::variant<std::string>>>>>
155*acb7cfb4SJennifer Lee           interfaces_properties;
156*acb7cfb4SJennifer Lee 
157*acb7cfb4SJennifer Lee       sdbusplus::message::object_path obj_path;
158*acb7cfb4SJennifer Lee 
159*acb7cfb4SJennifer Lee       m.read(obj_path, interfaces_properties);  // Read in the object path
160*acb7cfb4SJennifer Lee                                                 // that was just created
161*acb7cfb4SJennifer Lee       // std::string str_objpath = obj_path.str;  // keep a copy for
162*acb7cfb4SJennifer Lee       // constructing response message
163*acb7cfb4SJennifer Lee       BMCWEB_LOG_DEBUG << "obj path = " << obj_path.str;  // str_objpath;
164*acb7cfb4SJennifer Lee       for (auto &interface : interfaces_properties) {
165*acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "interface = " << interface.first;
166*acb7cfb4SJennifer Lee 
167*acb7cfb4SJennifer Lee         if (interface.first == "xyz.openbmc_project.Software.Activation") {
168*acb7cfb4SJennifer Lee           // cancel timer only when xyz.openbmc_project.Software.Activation
169*acb7cfb4SJennifer Lee           // interface is added
170*acb7cfb4SJennifer Lee           boost::system::error_code ec;
171*acb7cfb4SJennifer Lee           timeout.cancel(ec);
172*acb7cfb4SJennifer Lee           if (ec) {
173*acb7cfb4SJennifer Lee             BMCWEB_LOG_ERROR << "error canceling timer " << ec;
174*acb7cfb4SJennifer Lee           }
175*acb7cfb4SJennifer Lee           UpdateService::activateImage(obj_path.str);  // str_objpath);
176*acb7cfb4SJennifer Lee           res.jsonValue = redfish::messages::success();
177*acb7cfb4SJennifer Lee           BMCWEB_LOG_DEBUG << "ending response";
178*acb7cfb4SJennifer Lee           res.end();
179*acb7cfb4SJennifer Lee           fwUpdateMatcher = nullptr;
180*acb7cfb4SJennifer Lee         }
181*acb7cfb4SJennifer Lee       }
182*acb7cfb4SJennifer Lee     };
183*acb7cfb4SJennifer Lee 
184*acb7cfb4SJennifer Lee     fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
185*acb7cfb4SJennifer Lee         *crow::connections::systemBus,
186*acb7cfb4SJennifer Lee         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
187*acb7cfb4SJennifer Lee         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
188*acb7cfb4SJennifer Lee         callback);
189*acb7cfb4SJennifer Lee 
190*acb7cfb4SJennifer Lee     std::string filepath(
191*acb7cfb4SJennifer Lee         "/tmp/images/" +
192*acb7cfb4SJennifer Lee         boost::uuids::to_string(boost::uuids::random_generator()()));
193*acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
194*acb7cfb4SJennifer Lee     std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
195*acb7cfb4SJennifer Lee                                     std::ofstream::trunc);
196*acb7cfb4SJennifer Lee     out << req.body;
197*acb7cfb4SJennifer Lee     out.close();
198*acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "file upload complete!!";
199*acb7cfb4SJennifer Lee   }
200729dae72SJennifer Lee };
201729dae72SJennifer Lee 
202729dae72SJennifer Lee class SoftwareInventoryCollection : public Node {
203729dae72SJennifer Lee  public:
204729dae72SJennifer Lee   /*
205729dae72SJennifer Lee    * Default Constructor
206729dae72SJennifer Lee    */
207729dae72SJennifer Lee   template <typename CrowApp>
208729dae72SJennifer Lee   SoftwareInventoryCollection(CrowApp &app)
2096c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") {
210729dae72SJennifer Lee     Node::json["@odata.type"] =
211729dae72SJennifer Lee         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
2126c4eb9deSJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
213729dae72SJennifer Lee     Node::json["@odata.context"] =
214729dae72SJennifer Lee         "/redfish/v1/"
215729dae72SJennifer Lee         "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
216729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory Collection";
217729dae72SJennifer Lee 
218729dae72SJennifer Lee     entityPrivileges = {
219729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
220729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
221729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
222729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
223729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
224729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
225729dae72SJennifer Lee   }
226729dae72SJennifer Lee 
227729dae72SJennifer Lee  private:
228729dae72SJennifer Lee   /**
229729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
230729dae72SJennifer Lee    */
23155c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
232729dae72SJennifer Lee              const std::vector<std::string> &params) override {
23355c7b7a2SEd Tanous     res.jsonValue = Node::json;
234*acb7cfb4SJennifer Lee     softwareInventoryProvider.getAllSoftwareInventoryObject(
2356c4eb9deSJennifer Lee         [&](const bool &success,
2366c4eb9deSJennifer Lee             const std::vector<std::pair<
2376c4eb9deSJennifer Lee                 std::string,
2386c4eb9deSJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
2396c4eb9deSJennifer Lee                 &subtree) {
2406c4eb9deSJennifer Lee           if (!success) {
241729dae72SJennifer Lee             res.result(boost::beast::http::status::internal_server_error);
242*acb7cfb4SJennifer Lee             res.jsonValue = messages::internalError();
2436c4eb9deSJennifer Lee             res.end();
2446c4eb9deSJennifer Lee             return;
245729dae72SJennifer Lee           }
2466c4eb9deSJennifer Lee 
2476c4eb9deSJennifer Lee           if (subtree.empty()) {
24855c7b7a2SEd Tanous             BMCWEB_LOG_DEBUG << "subtree empty!!";
249*acb7cfb4SJennifer Lee             res.result(boost::beast::http::status::internal_server_error);
250*acb7cfb4SJennifer Lee             res.jsonValue = messages::internalError();
251729dae72SJennifer Lee             res.end();
2526c4eb9deSJennifer Lee             return;
2536c4eb9deSJennifer Lee           }
2546c4eb9deSJennifer Lee 
25555c7b7a2SEd Tanous           res.jsonValue["Members"] = nlohmann::json::array();
256*acb7cfb4SJennifer Lee           res.jsonValue["Members@odata.count"] = 0;
257*acb7cfb4SJennifer Lee 
258*acb7cfb4SJennifer Lee           std::shared_ptr<AsyncResp> asyncResp =
259*acb7cfb4SJennifer Lee               std::make_shared<AsyncResp>(res);
2606c4eb9deSJennifer Lee 
2616c4eb9deSJennifer Lee           for (auto &obj : subtree) {
2626c4eb9deSJennifer Lee             const std::vector<std::pair<std::string, std::vector<std::string>>>
2636c4eb9deSJennifer Lee                 &connections = obj.second;
2646c4eb9deSJennifer Lee 
265*acb7cfb4SJennifer Lee             // if can't parse fw id then return
266*acb7cfb4SJennifer Lee             std::size_t id_pos;
267*acb7cfb4SJennifer Lee             if ((id_pos = obj.first.rfind("/")) == std::string::npos) {
268*acb7cfb4SJennifer Lee               res.result(boost::beast::http::status::internal_server_error);
269*acb7cfb4SJennifer Lee               res.jsonValue = messages::internalError();
270*acb7cfb4SJennifer Lee               BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
271*acb7cfb4SJennifer Lee               res.end();
272*acb7cfb4SJennifer Lee               return;
273*acb7cfb4SJennifer Lee             }
274*acb7cfb4SJennifer Lee             std::string fw_id = obj.first.substr(id_pos + 1);
275*acb7cfb4SJennifer Lee 
276*acb7cfb4SJennifer Lee             for (const auto &conn : connections) {
2776c4eb9deSJennifer Lee               const std::string connectionName = conn.first;
27855c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "connectionName = " << connectionName;
27955c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
2806c4eb9deSJennifer Lee 
28155c7b7a2SEd Tanous               crow::connections::systemBus->async_method_call(
282*acb7cfb4SJennifer Lee                   [asyncResp, fw_id](
283*acb7cfb4SJennifer Lee                       const boost::system::error_code error_code,
284*acb7cfb4SJennifer Lee                       const sdbusplus::message::variant<std::string>
285*acb7cfb4SJennifer Lee                           &activation_status) {
28655c7b7a2SEd Tanous                     BMCWEB_LOG_DEBUG << "safe returned in lambda function";
2876c4eb9deSJennifer Lee                     if (error_code) {
288*acb7cfb4SJennifer Lee                       asyncResp->res.result(
2896c4eb9deSJennifer Lee                           boost::beast::http::status::internal_server_error);
290*acb7cfb4SJennifer Lee                       asyncResp->res.jsonValue = messages::internalError();
291*acb7cfb4SJennifer Lee                       asyncResp->res.end();
2926c4eb9deSJennifer Lee                       return;
2936c4eb9deSJennifer Lee                     }
294*acb7cfb4SJennifer Lee                     const std::string *activation_status_str =
295*acb7cfb4SJennifer Lee                         mapbox::getPtr<const std::string>(activation_status);
296*acb7cfb4SJennifer Lee                     if (activation_status_str != nullptr &&
297*acb7cfb4SJennifer Lee                         *activation_status_str !=
298*acb7cfb4SJennifer Lee                             "xyz.openbmc_project.Software.Activation."
299*acb7cfb4SJennifer Lee                             "Activations.Active") {
300*acb7cfb4SJennifer Lee                       // The activation status of this software is not currently
301*acb7cfb4SJennifer Lee                       // active, so does not need to be listed in the response
302*acb7cfb4SJennifer Lee                       return;
303*acb7cfb4SJennifer Lee                     }
304*acb7cfb4SJennifer Lee                     asyncResp->res.jsonValue["Members"].push_back(
3056c4eb9deSJennifer Lee                         {{"@odata.id",
3066c4eb9deSJennifer Lee                           "/redfish/v1/UpdateService/FirmwareInventory/" +
307*acb7cfb4SJennifer Lee                               fw_id}});
308*acb7cfb4SJennifer Lee                     asyncResp->res.jsonValue["Members@odata.count"] =
309*acb7cfb4SJennifer Lee                         asyncResp->res.jsonValue["Members"].size();
3106c4eb9deSJennifer Lee                   },
3116c4eb9deSJennifer Lee                   connectionName, obj.first, "org.freedesktop.DBus.Properties",
312*acb7cfb4SJennifer Lee                   "Get", "xyz.openbmc_project.Software.Activation",
313*acb7cfb4SJennifer Lee                   "Activation");
3146c4eb9deSJennifer Lee             }
3156c4eb9deSJennifer Lee           }
316729dae72SJennifer Lee         });
317729dae72SJennifer Lee   }
318*acb7cfb4SJennifer Lee 
31955c7b7a2SEd Tanous   OnDemandSoftwareInventoryProvider softwareInventoryProvider;
320729dae72SJennifer Lee };
321729dae72SJennifer Lee /**
322729dae72SJennifer Lee  * Chassis override class for delivering Chassis Schema
323729dae72SJennifer Lee  */
324729dae72SJennifer Lee class SoftwareInventory : public Node {
325729dae72SJennifer Lee  public:
326729dae72SJennifer Lee   /*
327729dae72SJennifer Lee    * Default Constructor
328729dae72SJennifer Lee    */
329729dae72SJennifer Lee   template <typename CrowApp>
330729dae72SJennifer Lee   SoftwareInventory(CrowApp &app)
3316c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
332729dae72SJennifer Lee              std::string()) {
333729dae72SJennifer Lee     Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
334729dae72SJennifer Lee     Node::json["@odata.context"] =
335729dae72SJennifer Lee         "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
336729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory";
3376c4eb9deSJennifer Lee     Node::json["Updateable"] = false;
338*acb7cfb4SJennifer Lee     Node::json["Status"]["Health"] = "OK";
339*acb7cfb4SJennifer Lee     Node::json["Status"]["HealthRollup"] = "OK";
340*acb7cfb4SJennifer Lee     Node::json["Status"]["State"] = "Enabled";
341729dae72SJennifer Lee     entityPrivileges = {
342729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
343729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
344729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
345729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
346729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
347729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
348729dae72SJennifer Lee   }
349729dae72SJennifer Lee 
350729dae72SJennifer Lee  private:
351729dae72SJennifer Lee   /**
352729dae72SJennifer Lee    * Functions triggers appropriate requests on DBus
353729dae72SJennifer Lee    */
35455c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
355729dae72SJennifer Lee              const std::vector<std::string> &params) override {
35655c7b7a2SEd Tanous     res.jsonValue = Node::json;
3576c4eb9deSJennifer Lee 
358729dae72SJennifer Lee     if (params.size() != 1) {
359729dae72SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
360*acb7cfb4SJennifer Lee       res.jsonValue = messages::internalError();
361729dae72SJennifer Lee       res.end();
362729dae72SJennifer Lee       return;
363729dae72SJennifer Lee     }
364729dae72SJennifer Lee 
365*acb7cfb4SJennifer Lee     const std::string &fw_id = params[0];
366*acb7cfb4SJennifer Lee     res.jsonValue["Id"] = fw_id;
36755c7b7a2SEd Tanous     res.jsonValue["@odata.id"] =
368*acb7cfb4SJennifer Lee         "/redfish/v1/UpdateService/FirmwareInventory/" + fw_id;
369*acb7cfb4SJennifer Lee     softwareInventoryProvider.getAllSoftwareInventoryObject([
370*acb7cfb4SJennifer Lee       &res, id{std::string(fw_id)}
371*acb7cfb4SJennifer Lee     ](const bool &success,
3726c4eb9deSJennifer Lee       const std::vector<std::pair<
3736c4eb9deSJennifer Lee           std::string,
3746c4eb9deSJennifer Lee           std::vector<std::pair<std::string, std::vector<std::string>>>>>
3756c4eb9deSJennifer Lee           &subtree) {
37655c7b7a2SEd Tanous       BMCWEB_LOG_DEBUG << "doGet callback...";
3776c4eb9deSJennifer Lee       if (!success) {
3786c4eb9deSJennifer Lee         res.result(boost::beast::http::status::internal_server_error);
379*acb7cfb4SJennifer Lee         res.jsonValue = messages::internalError();
380729dae72SJennifer Lee         res.end();
3816c4eb9deSJennifer Lee         return;
3826c4eb9deSJennifer Lee       }
3836c4eb9deSJennifer Lee 
3846c4eb9deSJennifer Lee       if (subtree.empty()) {
385*acb7cfb4SJennifer Lee         BMCWEB_LOG_ERROR << "subtree empty!!";
386*acb7cfb4SJennifer Lee         res.result(boost::beast::http::status::not_found);
3876c4eb9deSJennifer Lee         res.end();
3886c4eb9deSJennifer Lee         return;
3896c4eb9deSJennifer Lee       }
3906c4eb9deSJennifer Lee 
391*acb7cfb4SJennifer Lee       bool fw_id_found = false;
392*acb7cfb4SJennifer Lee 
3936c4eb9deSJennifer Lee       for (auto &obj : subtree) {
394*acb7cfb4SJennifer Lee         if (boost::ends_with(obj.first, id) != true) {
395*acb7cfb4SJennifer Lee           continue;
396*acb7cfb4SJennifer Lee         }
397*acb7cfb4SJennifer Lee         fw_id_found = true;
398*acb7cfb4SJennifer Lee 
3996c4eb9deSJennifer Lee         const std::vector<std::pair<std::string, std::vector<std::string>>>
4006c4eb9deSJennifer Lee             &connections = obj.second;
4016c4eb9deSJennifer Lee 
402*acb7cfb4SJennifer Lee         if (connections.size() <= 0) {
403*acb7cfb4SJennifer Lee           continue;
404*acb7cfb4SJennifer Lee         }
405*acb7cfb4SJennifer Lee         const std::pair<std::string, std::vector<std::string>> &conn =
406*acb7cfb4SJennifer Lee             connections[0];
407*acb7cfb4SJennifer Lee         const std::string &connectionName = conn.first;
40855c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "connectionName = " << connectionName;
40955c7b7a2SEd Tanous         BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
4106c4eb9deSJennifer Lee 
41155c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
412*acb7cfb4SJennifer Lee             [&res, id](
4136c4eb9deSJennifer Lee                 const boost::system::error_code error_code,
4146c4eb9deSJennifer Lee                 const boost::container::flat_map<std::string, VariantType>
4156c4eb9deSJennifer Lee                     &propertiesList) {
4166c4eb9deSJennifer Lee               if (error_code) {
417*acb7cfb4SJennifer Lee                 res.result(boost::beast::http::status::internal_server_error);
418*acb7cfb4SJennifer Lee                 res.jsonValue = messages::internalError();
4196c4eb9deSJennifer Lee                 res.end();
4206c4eb9deSJennifer Lee                 return;
4216c4eb9deSJennifer Lee               }
422*acb7cfb4SJennifer Lee 
4236c4eb9deSJennifer Lee               boost::container::flat_map<std::string,
4246c4eb9deSJennifer Lee                                          VariantType>::const_iterator it =
4256c4eb9deSJennifer Lee                   propertiesList.find("Purpose");
4266c4eb9deSJennifer Lee               if (it == propertiesList.end()) {
427*acb7cfb4SJennifer Lee                 BMCWEB_LOG_ERROR << "Can't find property \"Purpose\"!";
428*acb7cfb4SJennifer Lee                 res.result(boost::beast::http::status::internal_server_error);
429*acb7cfb4SJennifer Lee                 res.jsonValue = messages::internalError();
430*acb7cfb4SJennifer Lee                 res.end();
4316c4eb9deSJennifer Lee                 return;
4326c4eb9deSJennifer Lee               }
433*acb7cfb4SJennifer Lee 
434*acb7cfb4SJennifer Lee               // SoftwareId
435*acb7cfb4SJennifer Lee               const std::string *sw_inv_purpose =
436*acb7cfb4SJennifer Lee                   mapbox::getPtr<const std::string>(it->second);
437*acb7cfb4SJennifer Lee               if (sw_inv_purpose == nullptr) {
438*acb7cfb4SJennifer Lee                 res.jsonValue = redfish::messages::internalError();
439*acb7cfb4SJennifer Lee                 res.jsonValue = messages::internalError();
440*acb7cfb4SJennifer Lee                 return;
441*acb7cfb4SJennifer Lee               }
44255c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "sw_inv_purpose = " << sw_inv_purpose;
443*acb7cfb4SJennifer Lee               std::size_t last_pos = sw_inv_purpose->rfind(".");
444*acb7cfb4SJennifer Lee               if (last_pos != std::string::npos) {
445*acb7cfb4SJennifer Lee                 res.jsonValue["SoftwareId"] =
446*acb7cfb4SJennifer Lee                     sw_inv_purpose->substr(last_pos + 1);
447*acb7cfb4SJennifer Lee               } else {
448*acb7cfb4SJennifer Lee                 BMCWEB_LOG_ERROR << "Can't parse software purpose!";
449*acb7cfb4SJennifer Lee               }
450*acb7cfb4SJennifer Lee 
451*acb7cfb4SJennifer Lee               // Version
4526c4eb9deSJennifer Lee               it = propertiesList.find("Version");
453*acb7cfb4SJennifer Lee               if (it != propertiesList.end()) {
454*acb7cfb4SJennifer Lee                 const std::string *version =
455*acb7cfb4SJennifer Lee                     mapbox::getPtr<const std::string>(it->second);
456*acb7cfb4SJennifer Lee                 if (version == nullptr) {
457*acb7cfb4SJennifer Lee                   res.jsonValue = redfish::messages::internalError();
458*acb7cfb4SJennifer Lee                   res.jsonValue = messages::internalError();
4596c4eb9deSJennifer Lee                   return;
4606c4eb9deSJennifer Lee                 }
46155c7b7a2SEd Tanous                 res.jsonValue["Version"] =
46255c7b7a2SEd Tanous                     *(mapbox::getPtr<const std::string>(it->second));
463*acb7cfb4SJennifer Lee               } else {
464*acb7cfb4SJennifer Lee                 BMCWEB_LOG_DEBUG << "Can't find version info!";
4656c4eb9deSJennifer Lee               }
4666c4eb9deSJennifer Lee 
467*acb7cfb4SJennifer Lee               res.end();
4686c4eb9deSJennifer Lee             },
4696c4eb9deSJennifer Lee             connectionName, obj.first, "org.freedesktop.DBus.Properties",
4706c4eb9deSJennifer Lee             "GetAll", "xyz.openbmc_project.Software.Version");
4716c4eb9deSJennifer Lee       }
472*acb7cfb4SJennifer Lee       if (!fw_id_found) {
473*acb7cfb4SJennifer Lee         res.result(boost::beast::http::status::not_found);
474*acb7cfb4SJennifer Lee         res.end();
475*acb7cfb4SJennifer Lee         return;
4766c4eb9deSJennifer Lee       }
477729dae72SJennifer Lee     });
478729dae72SJennifer Lee   }
479729dae72SJennifer Lee 
48055c7b7a2SEd Tanous   OnDemandSoftwareInventoryProvider softwareInventoryProvider;
481729dae72SJennifer Lee };
482729dae72SJennifer Lee 
483729dae72SJennifer Lee }  // namespace redfish
484