xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision c711bf86b1cfd4c10e5516616315590ab8d9ae80)
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 {
22acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
23729dae72SJennifer Lee 
24729dae72SJennifer Lee class UpdateService : public Node {
25729dae72SJennifer Lee  public:
26729dae72SJennifer Lee   UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
27729dae72SJennifer Lee     Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
28729dae72SJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService";
29729dae72SJennifer Lee     Node::json["@odata.context"] =
30729dae72SJennifer Lee         "/redfish/v1/$metadata#UpdateService.UpdateService";
31729dae72SJennifer Lee     Node::json["Id"] = "UpdateService";
32729dae72SJennifer Lee     Node::json["Description"] = "Service for Software Update";
33729dae72SJennifer Lee     Node::json["Name"] = "Update Service";
34acb7cfb4SJennifer Lee     Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
35*c711bf86SEd Tanous     // UpdateService cannot be disabled
36*c711bf86SEd Tanous     Node::json["ServiceEnabled"] = true;
376c4eb9deSJennifer Lee     Node::json["FirmwareInventory"] = {
386c4eb9deSJennifer Lee         {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
39729dae72SJennifer Lee 
40729dae72SJennifer Lee     entityPrivileges = {
41729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
42729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
43729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
44729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
45729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
46729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
47729dae72SJennifer Lee   }
48729dae72SJennifer Lee 
49729dae72SJennifer Lee  private:
5055c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
51729dae72SJennifer Lee              const std::vector<std::string> &params) override {
5255c7b7a2SEd Tanous     res.jsonValue = Node::json;
53729dae72SJennifer Lee     res.end();
54729dae72SJennifer Lee   }
55*c711bf86SEd Tanous   static void activateImage(const std::string &objPath) {
56acb7cfb4SJennifer Lee     crow::connections::systemBus->async_method_call(
57*c711bf86SEd Tanous         [objPath](const boost::system::error_code error_code) {
58acb7cfb4SJennifer Lee           if (error_code) {
59acb7cfb4SJennifer Lee             BMCWEB_LOG_DEBUG << "error_code = " << error_code;
60acb7cfb4SJennifer Lee             BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
61acb7cfb4SJennifer Lee           }
62acb7cfb4SJennifer Lee         },
63*c711bf86SEd Tanous         "xyz.openbmc_project.Software.BMC.Updater", objPath,
64acb7cfb4SJennifer Lee         "org.freedesktop.DBus.Properties", "Set",
65acb7cfb4SJennifer Lee         "xyz.openbmc_project.Software.Activation", "RequestedActivation",
66acb7cfb4SJennifer Lee         sdbusplus::message::variant<std::string>(
67acb7cfb4SJennifer Lee             "xyz.openbmc_project.Software.Activation.RequestedActivations."
68acb7cfb4SJennifer Lee             "Active"));
69acb7cfb4SJennifer Lee   }
70acb7cfb4SJennifer Lee   void doPost(crow::Response &res, const crow::Request &req,
71acb7cfb4SJennifer Lee               const std::vector<std::string> &params) override {
72acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "doPost...";
73acb7cfb4SJennifer Lee 
74acb7cfb4SJennifer Lee     // Only allow one FW update at a time
75acb7cfb4SJennifer Lee     if (fwUpdateMatcher != nullptr) {
76acb7cfb4SJennifer Lee       res.addHeader("Retry-After", "30");
77acb7cfb4SJennifer Lee       res.result(boost::beast::http::status::service_unavailable);
78acb7cfb4SJennifer Lee       res.jsonValue = messages::serviceTemporarilyUnavailable("3");
79acb7cfb4SJennifer Lee       res.end();
80acb7cfb4SJennifer Lee       return;
81acb7cfb4SJennifer Lee     }
82acb7cfb4SJennifer Lee     // Make this const static so it survives outside this method
83acb7cfb4SJennifer Lee     static boost::asio::deadline_timer timeout(*req.ioService,
84acb7cfb4SJennifer Lee                                                boost::posix_time::seconds(5));
85acb7cfb4SJennifer Lee 
86acb7cfb4SJennifer Lee     timeout.expires_from_now(boost::posix_time::seconds(5));
87acb7cfb4SJennifer Lee 
88acb7cfb4SJennifer Lee     timeout.async_wait([&res](const boost::system::error_code &ec) {
89acb7cfb4SJennifer Lee       fwUpdateMatcher = nullptr;
90acb7cfb4SJennifer Lee       if (ec == boost::asio::error::operation_aborted) {
91acb7cfb4SJennifer Lee         // expected, we were canceled before the timer completed.
92acb7cfb4SJennifer Lee         return;
93acb7cfb4SJennifer Lee       }
94acb7cfb4SJennifer Lee       BMCWEB_LOG_ERROR << "Timed out waiting for firmware object being created";
95acb7cfb4SJennifer Lee       BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
96acb7cfb4SJennifer Lee       if (ec) {
97acb7cfb4SJennifer Lee         BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
98acb7cfb4SJennifer Lee         return;
99acb7cfb4SJennifer Lee       }
100acb7cfb4SJennifer Lee 
101acb7cfb4SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
102acb7cfb4SJennifer Lee       res.jsonValue = redfish::messages::internalError();
103acb7cfb4SJennifer Lee       res.end();
104acb7cfb4SJennifer Lee     });
105acb7cfb4SJennifer Lee 
106acb7cfb4SJennifer Lee     auto callback = [&res](sdbusplus::message::message &m) {
107acb7cfb4SJennifer Lee       BMCWEB_LOG_DEBUG << "Match fired";
108acb7cfb4SJennifer Lee       bool flag = false;
109acb7cfb4SJennifer Lee 
110acb7cfb4SJennifer Lee       if (m.is_method_error()) {
111acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "Dbus method error!!!";
112acb7cfb4SJennifer Lee         res.end();
113acb7cfb4SJennifer Lee         return;
114acb7cfb4SJennifer Lee       }
115acb7cfb4SJennifer Lee       std::vector<std::pair<
116acb7cfb4SJennifer Lee           std::string,
117acb7cfb4SJennifer Lee           std::vector<std::pair<std::string,
118acb7cfb4SJennifer Lee                                 sdbusplus::message::variant<std::string>>>>>
119acb7cfb4SJennifer Lee           interfaces_properties;
120acb7cfb4SJennifer Lee 
121*c711bf86SEd Tanous       sdbusplus::message::object_path objPath;
122acb7cfb4SJennifer Lee 
123*c711bf86SEd Tanous       m.read(objPath, interfaces_properties);  // Read in the object path
124acb7cfb4SJennifer Lee                                                // that was just created
125*c711bf86SEd Tanous       // std::string str_objpath = objPath.str;  // keep a copy for
126acb7cfb4SJennifer Lee       // constructing response message
127*c711bf86SEd Tanous       BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;  // str_objpath;
128acb7cfb4SJennifer Lee       for (auto &interface : interfaces_properties) {
129acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "interface = " << interface.first;
130acb7cfb4SJennifer Lee 
131acb7cfb4SJennifer Lee         if (interface.first == "xyz.openbmc_project.Software.Activation") {
132acb7cfb4SJennifer Lee           // cancel timer only when xyz.openbmc_project.Software.Activation
133acb7cfb4SJennifer Lee           // interface is added
134acb7cfb4SJennifer Lee           boost::system::error_code ec;
135acb7cfb4SJennifer Lee           timeout.cancel(ec);
136acb7cfb4SJennifer Lee           if (ec) {
137acb7cfb4SJennifer Lee             BMCWEB_LOG_ERROR << "error canceling timer " << ec;
138acb7cfb4SJennifer Lee           }
139*c711bf86SEd Tanous           UpdateService::activateImage(objPath.str);  // str_objpath);
140acb7cfb4SJennifer Lee           res.jsonValue = redfish::messages::success();
141acb7cfb4SJennifer Lee           BMCWEB_LOG_DEBUG << "ending response";
142acb7cfb4SJennifer Lee           res.end();
143acb7cfb4SJennifer Lee           fwUpdateMatcher = nullptr;
144acb7cfb4SJennifer Lee         }
145acb7cfb4SJennifer Lee       }
146acb7cfb4SJennifer Lee     };
147acb7cfb4SJennifer Lee 
148acb7cfb4SJennifer Lee     fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
149acb7cfb4SJennifer Lee         *crow::connections::systemBus,
150acb7cfb4SJennifer Lee         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
151acb7cfb4SJennifer Lee         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
152acb7cfb4SJennifer Lee         callback);
153acb7cfb4SJennifer Lee 
154acb7cfb4SJennifer Lee     std::string filepath(
155acb7cfb4SJennifer Lee         "/tmp/images/" +
156acb7cfb4SJennifer Lee         boost::uuids::to_string(boost::uuids::random_generator()()));
157acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
158acb7cfb4SJennifer Lee     std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
159acb7cfb4SJennifer Lee                                     std::ofstream::trunc);
160acb7cfb4SJennifer Lee     out << req.body;
161acb7cfb4SJennifer Lee     out.close();
162acb7cfb4SJennifer Lee     BMCWEB_LOG_DEBUG << "file upload complete!!";
163acb7cfb4SJennifer Lee   }
164729dae72SJennifer Lee };
165729dae72SJennifer Lee 
166729dae72SJennifer Lee class SoftwareInventoryCollection : public Node {
167729dae72SJennifer Lee  public:
168729dae72SJennifer Lee   template <typename CrowApp>
169729dae72SJennifer Lee   SoftwareInventoryCollection(CrowApp &app)
1706c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") {
171729dae72SJennifer Lee     Node::json["@odata.type"] =
172729dae72SJennifer Lee         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1736c4eb9deSJennifer Lee     Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
174729dae72SJennifer Lee     Node::json["@odata.context"] =
175729dae72SJennifer Lee         "/redfish/v1/"
176729dae72SJennifer Lee         "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
177729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory Collection";
178729dae72SJennifer Lee 
179729dae72SJennifer Lee     entityPrivileges = {
180729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
181729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
182729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
183729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
184729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
185729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
186729dae72SJennifer Lee   }
187729dae72SJennifer Lee 
188729dae72SJennifer Lee  private:
18955c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
190729dae72SJennifer Lee              const std::vector<std::string> &params) override {
191*c711bf86SEd Tanous     std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19255c7b7a2SEd Tanous     res.jsonValue = Node::json;
193*c711bf86SEd Tanous 
194*c711bf86SEd Tanous     crow::connections::systemBus->async_method_call(
195*c711bf86SEd Tanous         [asyncResp](
196*c711bf86SEd Tanous             const boost::system::error_code ec,
1976c4eb9deSJennifer Lee             const std::vector<std::pair<
1986c4eb9deSJennifer Lee                 std::string,
1996c4eb9deSJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
2006c4eb9deSJennifer Lee                 &subtree) {
201*c711bf86SEd Tanous           if (ec) {
202*c711bf86SEd Tanous             asyncResp->res.result(
203*c711bf86SEd Tanous                 boost::beast::http::status::internal_server_error);
2046c4eb9deSJennifer Lee             return;
205729dae72SJennifer Lee           }
206*c711bf86SEd Tanous           asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
207*c711bf86SEd Tanous           asyncResp->res.jsonValue["Members@odata.count"] = 0;
2086c4eb9deSJennifer Lee 
2096c4eb9deSJennifer Lee           for (auto &obj : subtree) {
2106c4eb9deSJennifer Lee             const std::vector<std::pair<std::string, std::vector<std::string>>>
2116c4eb9deSJennifer Lee                 &connections = obj.second;
2126c4eb9deSJennifer Lee 
213*c711bf86SEd Tanous             for (auto &conn : connections) {
214*c711bf86SEd Tanous               const std::string &connectionName = conn.first;
21555c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "connectionName = " << connectionName;
21655c7b7a2SEd Tanous               BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
2176c4eb9deSJennifer Lee 
21855c7b7a2SEd Tanous               crow::connections::systemBus->async_method_call(
219*c711bf86SEd Tanous                   [asyncResp](const boost::system::error_code error_code,
220*c711bf86SEd Tanous                               const VariantType &activation) {
22155c7b7a2SEd Tanous                     BMCWEB_LOG_DEBUG << "safe returned in lambda function";
2226c4eb9deSJennifer Lee                     if (error_code) {
223acb7cfb4SJennifer Lee                       asyncResp->res.result(
2246c4eb9deSJennifer Lee                           boost::beast::http::status::internal_server_error);
2256c4eb9deSJennifer Lee                       return;
2266c4eb9deSJennifer Lee                     }
227*c711bf86SEd Tanous 
228*c711bf86SEd Tanous                     const std::string *sw_inv_purpose =
229*c711bf86SEd Tanous                         mapbox::getPtr<const std::string>(activation);
230*c711bf86SEd Tanous                     if (sw_inv_purpose == nullptr) {
231*c711bf86SEd Tanous                       asyncResp->res.result(
232*c711bf86SEd Tanous                           boost::beast::http::status::internal_server_error);
233acb7cfb4SJennifer Lee                       return;
234acb7cfb4SJennifer Lee                     }
235*c711bf86SEd Tanous                     std::size_t last_pos = sw_inv_purpose->rfind(".");
236*c711bf86SEd Tanous                     if (last_pos == std::string::npos) {
237*c711bf86SEd Tanous                       asyncResp->res.result(
238*c711bf86SEd Tanous                           boost::beast::http::status::internal_server_error);
239*c711bf86SEd Tanous                       return;
240*c711bf86SEd Tanous                     }
241*c711bf86SEd Tanous                     nlohmann::json &members =
242*c711bf86SEd Tanous                         asyncResp->res.jsonValue["Members"];
243*c711bf86SEd Tanous                     members.push_back(
2446c4eb9deSJennifer Lee                         {{"@odata.id",
2456c4eb9deSJennifer Lee                           "/redfish/v1/UpdateService/FirmwareInventory/" +
246*c711bf86SEd Tanous                               sw_inv_purpose->substr(last_pos + 1)}});
247acb7cfb4SJennifer Lee                     asyncResp->res.jsonValue["Members@odata.count"] =
248*c711bf86SEd Tanous                         members.size();
2496c4eb9deSJennifer Lee                   },
2506c4eb9deSJennifer Lee                   connectionName, obj.first, "org.freedesktop.DBus.Properties",
251acb7cfb4SJennifer Lee                   "Get", "xyz.openbmc_project.Software.Activation",
252acb7cfb4SJennifer Lee                   "Activation");
2536c4eb9deSJennifer Lee             }
2546c4eb9deSJennifer Lee           }
255*c711bf86SEd Tanous         },
256*c711bf86SEd Tanous         "xyz.openbmc_project.ObjectMapper",
257*c711bf86SEd Tanous         "/xyz/openbmc_project/object_mapper",
258*c711bf86SEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
259*c711bf86SEd Tanous         "/xyz/openbmc_project/software", int32_t(1),
260*c711bf86SEd Tanous         std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
261729dae72SJennifer Lee   }
262729dae72SJennifer Lee };
263*c711bf86SEd Tanous 
264729dae72SJennifer Lee class SoftwareInventory : public Node {
265729dae72SJennifer Lee  public:
266729dae72SJennifer Lee   template <typename CrowApp>
267729dae72SJennifer Lee   SoftwareInventory(CrowApp &app)
2686c4eb9deSJennifer Lee       : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
269729dae72SJennifer Lee              std::string()) {
270729dae72SJennifer Lee     Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
271729dae72SJennifer Lee     Node::json["@odata.context"] =
272729dae72SJennifer Lee         "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
273729dae72SJennifer Lee     Node::json["Name"] = "Software Inventory";
2746c4eb9deSJennifer Lee     Node::json["Updateable"] = false;
275acb7cfb4SJennifer Lee     Node::json["Status"]["Health"] = "OK";
276acb7cfb4SJennifer Lee     Node::json["Status"]["HealthRollup"] = "OK";
277acb7cfb4SJennifer Lee     Node::json["Status"]["State"] = "Enabled";
278729dae72SJennifer Lee     entityPrivileges = {
279729dae72SJennifer Lee         {boost::beast::http::verb::get, {{"Login"}}},
280729dae72SJennifer Lee         {boost::beast::http::verb::head, {{"Login"}}},
281729dae72SJennifer Lee         {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
282729dae72SJennifer Lee         {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
283729dae72SJennifer Lee         {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
284729dae72SJennifer Lee         {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
285729dae72SJennifer Lee   }
286729dae72SJennifer Lee 
287729dae72SJennifer Lee  private:
28855c7b7a2SEd Tanous   void doGet(crow::Response &res, const crow::Request &req,
289729dae72SJennifer Lee              const std::vector<std::string> &params) override {
290*c711bf86SEd Tanous     std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
29155c7b7a2SEd Tanous     res.jsonValue = Node::json;
2926c4eb9deSJennifer Lee 
293729dae72SJennifer Lee     if (params.size() != 1) {
294729dae72SJennifer Lee       res.result(boost::beast::http::status::internal_server_error);
295acb7cfb4SJennifer Lee       res.jsonValue = messages::internalError();
296729dae72SJennifer Lee       res.end();
297729dae72SJennifer Lee       return;
298729dae72SJennifer Lee     }
299729dae72SJennifer Lee 
300*c711bf86SEd Tanous     std::shared_ptr<std::string> sw_id =
301*c711bf86SEd Tanous         std::make_shared<std::string>(params[0]);
302*c711bf86SEd Tanous 
30355c7b7a2SEd Tanous     res.jsonValue["@odata.id"] =
304*c711bf86SEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory/" + *sw_id;
305*c711bf86SEd Tanous 
306*c711bf86SEd Tanous     crow::connections::systemBus->async_method_call(
307*c711bf86SEd Tanous         [asyncResp, sw_id](
308*c711bf86SEd Tanous             const boost::system::error_code ec,
3096c4eb9deSJennifer Lee             const std::vector<std::pair<
3106c4eb9deSJennifer Lee                 std::string,
3116c4eb9deSJennifer Lee                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
3126c4eb9deSJennifer Lee                 &subtree) {
31355c7b7a2SEd Tanous           BMCWEB_LOG_DEBUG << "doGet callback...";
314*c711bf86SEd Tanous           if (ec) {
315*c711bf86SEd Tanous             asyncResp->res.result(
316*c711bf86SEd Tanous                 boost::beast::http::status::internal_server_error);
3176c4eb9deSJennifer Lee             return;
3186c4eb9deSJennifer Lee           }
3196c4eb9deSJennifer Lee 
320*c711bf86SEd Tanous           for (const std::pair<std::string,
321*c711bf86SEd Tanous                                std::vector<std::pair<std::string,
322*c711bf86SEd Tanous                                                      std::vector<std::string>>>>
323*c711bf86SEd Tanous                    &obj : subtree) {
324*c711bf86SEd Tanous             if (boost::ends_with(obj.first, *sw_id) != true) {
325acb7cfb4SJennifer Lee               continue;
326acb7cfb4SJennifer Lee             }
327acb7cfb4SJennifer Lee 
328*c711bf86SEd Tanous             if (obj.second.size() <= 1) {
329acb7cfb4SJennifer Lee               continue;
330acb7cfb4SJennifer Lee             }
3316c4eb9deSJennifer Lee 
33255c7b7a2SEd Tanous             crow::connections::systemBus->async_method_call(
333*c711bf86SEd Tanous                 [asyncResp, sw_id](
3346c4eb9deSJennifer Lee                     const boost::system::error_code error_code,
3356c4eb9deSJennifer Lee                     const boost::container::flat_map<std::string, VariantType>
3366c4eb9deSJennifer Lee                         &propertiesList) {
3376c4eb9deSJennifer Lee                   if (error_code) {
338*c711bf86SEd Tanous                     asyncResp->res.result(
339*c711bf86SEd Tanous                         boost::beast::http::status::internal_server_error);
3406c4eb9deSJennifer Lee                     return;
3416c4eb9deSJennifer Lee                   }
3426c4eb9deSJennifer Lee                   boost::container::flat_map<std::string,
3436c4eb9deSJennifer Lee                                              VariantType>::const_iterator it =
3446c4eb9deSJennifer Lee                       propertiesList.find("Purpose");
3456c4eb9deSJennifer Lee                   if (it == propertiesList.end()) {
346*c711bf86SEd Tanous                     BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
347*c711bf86SEd Tanous                     asyncResp->res.result(
348*c711bf86SEd Tanous                         boost::beast::http::status::internal_server_error);
3496c4eb9deSJennifer Lee                     return;
3506c4eb9deSJennifer Lee                   }
351acb7cfb4SJennifer Lee                   const std::string *sw_inv_purpose =
352acb7cfb4SJennifer Lee                       mapbox::getPtr<const std::string>(it->second);
353acb7cfb4SJennifer Lee                   if (sw_inv_purpose == nullptr) {
354*c711bf86SEd Tanous                     BMCWEB_LOG_DEBUG << "wrong types for property\"Purpose\"!";
355*c711bf86SEd Tanous                     asyncResp->res.result(
356*c711bf86SEd Tanous                         boost::beast::http::status::internal_server_error);
357acb7cfb4SJennifer Lee                     return;
358acb7cfb4SJennifer Lee                   }
359*c711bf86SEd Tanous 
360*c711bf86SEd Tanous                   BMCWEB_LOG_DEBUG << "sw_inv_purpose = " << *sw_inv_purpose;
361*c711bf86SEd Tanous                   if (boost::ends_with(*sw_inv_purpose, "." + *sw_id)) {
362*c711bf86SEd Tanous                     it = propertiesList.find("Version");
363*c711bf86SEd Tanous                     if (it == propertiesList.end()) {
364*c711bf86SEd Tanous                       BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
365*c711bf86SEd Tanous                       asyncResp->res.result(
366*c711bf86SEd Tanous                           boost::beast::http::status::internal_server_error);
367*c711bf86SEd Tanous                       return;
368acb7cfb4SJennifer Lee                     }
369acb7cfb4SJennifer Lee 
370acb7cfb4SJennifer Lee                     const std::string *version =
371acb7cfb4SJennifer Lee                         mapbox::getPtr<const std::string>(it->second);
372*c711bf86SEd Tanous 
373*c711bf86SEd Tanous                     if (version != nullptr) {
374*c711bf86SEd Tanous                       BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
375*c711bf86SEd Tanous                       asyncResp->res.result(
376*c711bf86SEd Tanous                           boost::beast::http::status::internal_server_error);
3776c4eb9deSJennifer Lee                       return;
3786c4eb9deSJennifer Lee                     }
379*c711bf86SEd Tanous                     asyncResp->res.jsonValue["Version"] = *version;
380*c711bf86SEd Tanous                     asyncResp->res.jsonValue["Id"] = *sw_id;
3816c4eb9deSJennifer Lee                   }
3826c4eb9deSJennifer Lee                 },
383*c711bf86SEd Tanous                 obj.second[0].first, obj.first,
384*c711bf86SEd Tanous                 "org.freedesktop.DBus.Properties", "GetAll",
385*c711bf86SEd Tanous                 "xyz.openbmc_project.Software.Version");
3866c4eb9deSJennifer Lee           }
387*c711bf86SEd Tanous         },
388*c711bf86SEd Tanous         "xyz.openbmc_project.ObjectMapper",
389*c711bf86SEd Tanous         "/xyz/openbmc_project/object_mapper",
390*c711bf86SEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
391*c711bf86SEd Tanous         "/xyz/openbmc_project/software", int32_t(1),
392*c711bf86SEd Tanous         std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
3936c4eb9deSJennifer Lee   }
394729dae72SJennifer Lee };
395729dae72SJennifer Lee 
396729dae72SJennifer Lee }  // namespace redfish
397