xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision 87d847298c57168b1af9bc8bbf201073ef3e76fe)
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"
191abe55efSEd Tanous 
20729dae72SJennifer Lee #include <boost/container/flat_map.hpp>
21*87d84729SAndrew Geissler #include <utils/fw_utils.hpp>
22abf2add6SEd Tanous #include <variant>
23729dae72SJennifer Lee 
241abe55efSEd Tanous namespace redfish
251abe55efSEd Tanous {
2627826b5fSEd Tanous 
27acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
28729dae72SJennifer Lee 
291abe55efSEd Tanous class UpdateService : public Node
301abe55efSEd Tanous {
31729dae72SJennifer Lee   public:
321abe55efSEd Tanous     UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/")
331abe55efSEd Tanous     {
34729dae72SJennifer Lee         entityPrivileges = {
35729dae72SJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
36729dae72SJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
37729dae72SJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
38729dae72SJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
39729dae72SJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
40729dae72SJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
41729dae72SJennifer Lee     }
42729dae72SJennifer Lee 
43729dae72SJennifer Lee   private:
4455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
451abe55efSEd Tanous                const std::vector<std::string> &params) override
461abe55efSEd Tanous     {
470f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
480f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
490f74e643SEd Tanous         res.jsonValue["@odata.context"] =
500f74e643SEd Tanous             "/redfish/v1/$metadata#UpdateService.UpdateService";
510f74e643SEd Tanous         res.jsonValue["Id"] = "UpdateService";
520f74e643SEd Tanous         res.jsonValue["Description"] = "Service for Software Update";
530f74e643SEd Tanous         res.jsonValue["Name"] = "Update Service";
540f74e643SEd Tanous         res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
550f74e643SEd Tanous         // UpdateService cannot be disabled
560f74e643SEd Tanous         res.jsonValue["ServiceEnabled"] = true;
570f74e643SEd Tanous         res.jsonValue["FirmwareInventory"] = {
580f74e643SEd Tanous             {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
59729dae72SJennifer Lee         res.end();
60729dae72SJennifer Lee     }
611abe55efSEd Tanous     static void activateImage(const std::string &objPath)
621abe55efSEd Tanous     {
63acb7cfb4SJennifer Lee         crow::connections::systemBus->async_method_call(
64c711bf86SEd Tanous             [objPath](const boost::system::error_code error_code) {
651abe55efSEd Tanous                 if (error_code)
661abe55efSEd Tanous                 {
67acb7cfb4SJennifer Lee                     BMCWEB_LOG_DEBUG << "error_code = " << error_code;
68acb7cfb4SJennifer Lee                     BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
69acb7cfb4SJennifer Lee                 }
70acb7cfb4SJennifer Lee             },
71c711bf86SEd Tanous             "xyz.openbmc_project.Software.BMC.Updater", objPath,
72acb7cfb4SJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
73acb7cfb4SJennifer Lee             "xyz.openbmc_project.Software.Activation", "RequestedActivation",
74abf2add6SEd Tanous             std::variant<std::string>(
75acb7cfb4SJennifer Lee                 "xyz.openbmc_project.Software.Activation.RequestedActivations."
76acb7cfb4SJennifer Lee                 "Active"));
77acb7cfb4SJennifer Lee     }
78acb7cfb4SJennifer Lee     void doPost(crow::Response &res, const crow::Request &req,
791abe55efSEd Tanous                 const std::vector<std::string> &params) override
801abe55efSEd Tanous     {
81acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "doPost...";
82acb7cfb4SJennifer Lee 
83acb7cfb4SJennifer Lee         // Only allow one FW update at a time
841abe55efSEd Tanous         if (fwUpdateMatcher != nullptr)
851abe55efSEd Tanous         {
86acb7cfb4SJennifer Lee             res.addHeader("Retry-After", "30");
87f12894f8SJason M. Bills             messages::serviceTemporarilyUnavailable(res, "3");
88acb7cfb4SJennifer Lee             res.end();
89acb7cfb4SJennifer Lee             return;
90acb7cfb4SJennifer Lee         }
91acb7cfb4SJennifer Lee         // Make this const static so it survives outside this method
921abe55efSEd Tanous         static boost::asio::deadline_timer timeout(
931abe55efSEd Tanous             *req.ioService, boost::posix_time::seconds(5));
94acb7cfb4SJennifer Lee 
95acb7cfb4SJennifer Lee         timeout.expires_from_now(boost::posix_time::seconds(5));
96acb7cfb4SJennifer Lee 
97acb7cfb4SJennifer Lee         timeout.async_wait([&res](const boost::system::error_code &ec) {
98acb7cfb4SJennifer Lee             fwUpdateMatcher = nullptr;
991abe55efSEd Tanous             if (ec == boost::asio::error::operation_aborted)
1001abe55efSEd Tanous             {
101acb7cfb4SJennifer Lee                 // expected, we were canceled before the timer completed.
102acb7cfb4SJennifer Lee                 return;
103acb7cfb4SJennifer Lee             }
1041abe55efSEd Tanous             BMCWEB_LOG_ERROR
1051abe55efSEd Tanous                 << "Timed out waiting for firmware object being created";
1061abe55efSEd Tanous             BMCWEB_LOG_ERROR
1071abe55efSEd Tanous                 << "FW image may has already been uploaded to server";
1081abe55efSEd Tanous             if (ec)
1091abe55efSEd Tanous             {
110acb7cfb4SJennifer Lee                 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
111acb7cfb4SJennifer Lee                 return;
112acb7cfb4SJennifer Lee             }
113acb7cfb4SJennifer Lee 
114f12894f8SJason M. Bills             redfish::messages::internalError(res);
115acb7cfb4SJennifer Lee             res.end();
116acb7cfb4SJennifer Lee         });
117acb7cfb4SJennifer Lee 
118acb7cfb4SJennifer Lee         auto callback = [&res](sdbusplus::message::message &m) {
119acb7cfb4SJennifer Lee             BMCWEB_LOG_DEBUG << "Match fired";
120acb7cfb4SJennifer Lee 
1211abe55efSEd Tanous             if (m.is_method_error())
1221abe55efSEd Tanous             {
123acb7cfb4SJennifer Lee                 BMCWEB_LOG_DEBUG << "Dbus method error!!!";
124acb7cfb4SJennifer Lee                 res.end();
125acb7cfb4SJennifer Lee                 return;
126acb7cfb4SJennifer Lee             }
127acb7cfb4SJennifer Lee             std::vector<std::pair<
128acb7cfb4SJennifer Lee                 std::string,
129abf2add6SEd Tanous                 std::vector<std::pair<std::string, std::variant<std::string>>>>>
1303ae837c9SEd Tanous                 interfacesProperties;
131acb7cfb4SJennifer Lee 
132c711bf86SEd Tanous             sdbusplus::message::object_path objPath;
133acb7cfb4SJennifer Lee 
1343ae837c9SEd Tanous             m.read(objPath, interfacesProperties); // Read in the object path
135acb7cfb4SJennifer Lee                                                    // that was just created
136c711bf86SEd Tanous             // std::string str_objpath = objPath.str;  // keep a copy for
137acb7cfb4SJennifer Lee             // constructing response message
138c711bf86SEd Tanous             BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; // str_objpath;
1393ae837c9SEd Tanous             for (auto &interface : interfacesProperties)
1401abe55efSEd Tanous             {
141acb7cfb4SJennifer Lee                 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
142acb7cfb4SJennifer Lee 
1431abe55efSEd Tanous                 if (interface.first ==
1441abe55efSEd Tanous                     "xyz.openbmc_project.Software.Activation")
1451abe55efSEd Tanous                 {
1461abe55efSEd Tanous                     // cancel timer only when
1471abe55efSEd Tanous                     // xyz.openbmc_project.Software.Activation interface is
1481abe55efSEd Tanous                     // added
149acb7cfb4SJennifer Lee                     boost::system::error_code ec;
150acb7cfb4SJennifer Lee                     timeout.cancel(ec);
1511abe55efSEd Tanous                     if (ec)
1521abe55efSEd Tanous                     {
153acb7cfb4SJennifer Lee                         BMCWEB_LOG_ERROR << "error canceling timer " << ec;
154acb7cfb4SJennifer Lee                     }
155c711bf86SEd Tanous                     UpdateService::activateImage(objPath.str); // str_objpath);
156f12894f8SJason M. Bills                     redfish::messages::success(res);
157acb7cfb4SJennifer Lee                     BMCWEB_LOG_DEBUG << "ending response";
158acb7cfb4SJennifer Lee                     res.end();
159acb7cfb4SJennifer Lee                     fwUpdateMatcher = nullptr;
160acb7cfb4SJennifer Lee                 }
161acb7cfb4SJennifer Lee             }
162acb7cfb4SJennifer Lee         };
163acb7cfb4SJennifer Lee 
164acb7cfb4SJennifer Lee         fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
165acb7cfb4SJennifer Lee             *crow::connections::systemBus,
166acb7cfb4SJennifer Lee             "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
167acb7cfb4SJennifer Lee             "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
168acb7cfb4SJennifer Lee             callback);
169acb7cfb4SJennifer Lee 
170acb7cfb4SJennifer Lee         std::string filepath(
171acb7cfb4SJennifer Lee             "/tmp/images/" +
172acb7cfb4SJennifer Lee             boost::uuids::to_string(boost::uuids::random_generator()()));
173acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
174acb7cfb4SJennifer Lee         std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
175acb7cfb4SJennifer Lee                                         std::ofstream::trunc);
176acb7cfb4SJennifer Lee         out << req.body;
177acb7cfb4SJennifer Lee         out.close();
178acb7cfb4SJennifer Lee         BMCWEB_LOG_DEBUG << "file upload complete!!";
179acb7cfb4SJennifer Lee     }
180729dae72SJennifer Lee };
181729dae72SJennifer Lee 
1821abe55efSEd Tanous class SoftwareInventoryCollection : public Node
1831abe55efSEd Tanous {
184729dae72SJennifer Lee   public:
185729dae72SJennifer Lee     template <typename CrowApp>
1861abe55efSEd Tanous     SoftwareInventoryCollection(CrowApp &app) :
1871abe55efSEd Tanous         Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1881abe55efSEd Tanous     {
189729dae72SJennifer Lee         entityPrivileges = {
190729dae72SJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
191729dae72SJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
192729dae72SJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
193729dae72SJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
194729dae72SJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
195729dae72SJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
196729dae72SJennifer Lee     }
197729dae72SJennifer Lee 
198729dae72SJennifer Lee   private:
19955c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
2001abe55efSEd Tanous                const std::vector<std::string> &params) override
2011abe55efSEd Tanous     {
202c711bf86SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2030f74e643SEd Tanous         res.jsonValue["@odata.type"] =
2040f74e643SEd Tanous             "#SoftwareInventoryCollection.SoftwareInventoryCollection";
2050f74e643SEd Tanous         res.jsonValue["@odata.id"] =
2060f74e643SEd Tanous             "/redfish/v1/UpdateService/FirmwareInventory";
2070f74e643SEd Tanous         res.jsonValue["@odata.context"] =
2080f74e643SEd Tanous             "/redfish/v1/"
2090f74e643SEd Tanous             "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
2100f74e643SEd Tanous         res.jsonValue["Name"] = "Software Inventory Collection";
211c711bf86SEd Tanous 
212c711bf86SEd Tanous         crow::connections::systemBus->async_method_call(
213c711bf86SEd Tanous             [asyncResp](
214c711bf86SEd Tanous                 const boost::system::error_code ec,
2156c4eb9deSJennifer Lee                 const std::vector<std::pair<
2161abe55efSEd Tanous                     std::string, std::vector<std::pair<
2171abe55efSEd Tanous                                      std::string, std::vector<std::string>>>>>
2186c4eb9deSJennifer Lee                     &subtree) {
2191abe55efSEd Tanous                 if (ec)
2201abe55efSEd Tanous                 {
221f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
2226c4eb9deSJennifer Lee                     return;
223729dae72SJennifer Lee                 }
224c711bf86SEd Tanous                 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
225c711bf86SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = 0;
2266c4eb9deSJennifer Lee 
2271abe55efSEd Tanous                 for (auto &obj : subtree)
2281abe55efSEd Tanous                 {
2291abe55efSEd Tanous                     const std::vector<
2301abe55efSEd Tanous                         std::pair<std::string, std::vector<std::string>>>
2316c4eb9deSJennifer Lee                         &connections = obj.second;
2326c4eb9deSJennifer Lee 
233f4b65ab1SJennifer Lee                     // if can't parse fw id then return
23427826b5fSEd Tanous                     std::size_t idPos;
23527826b5fSEd Tanous                     if ((idPos = obj.first.rfind("/")) == std::string::npos)
236f4b65ab1SJennifer Lee                     {
237f12894f8SJason M. Bills                         messages::internalError(asyncResp->res);
238f4b65ab1SJennifer Lee                         BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
239f4b65ab1SJennifer Lee                         return;
240f4b65ab1SJennifer Lee                     }
241f4b65ab1SJennifer Lee                     std::string swId = obj.first.substr(idPos + 1);
242f4b65ab1SJennifer Lee 
2431abe55efSEd Tanous                     for (auto &conn : connections)
2441abe55efSEd Tanous                     {
245c711bf86SEd Tanous                         const std::string &connectionName = conn.first;
2461abe55efSEd Tanous                         BMCWEB_LOG_DEBUG << "connectionName = "
2471abe55efSEd Tanous                                          << connectionName;
24855c7b7a2SEd Tanous                         BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
2496c4eb9deSJennifer Lee 
25055c7b7a2SEd Tanous                         crow::connections::systemBus->async_method_call(
251f4b65ab1SJennifer Lee                             [asyncResp,
252f4b65ab1SJennifer Lee                              swId](const boost::system::error_code error_code,
253c711bf86SEd Tanous                                    const VariantType &activation) {
2541abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
2551abe55efSEd Tanous                                     << "safe returned in lambda function";
2561abe55efSEd Tanous                                 if (error_code)
2571abe55efSEd Tanous                                 {
258f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
2596c4eb9deSJennifer Lee                                     return;
2606c4eb9deSJennifer Lee                                 }
261c711bf86SEd Tanous 
262f4b65ab1SJennifer Lee                                 const std::string *swActivationStatus =
263abf2add6SEd Tanous                                     std::get_if<std::string>(&activation);
264f4b65ab1SJennifer Lee                                 if (swActivationStatus == nullptr)
2651abe55efSEd Tanous                                 {
266f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
267acb7cfb4SJennifer Lee                                     return;
268acb7cfb4SJennifer Lee                                 }
269f4b65ab1SJennifer Lee                                 if (swActivationStatus != nullptr &&
270f4b65ab1SJennifer Lee                                     *swActivationStatus !=
271f4b65ab1SJennifer Lee                                         "xyz.openbmc_project.Software."
272f4b65ab1SJennifer Lee                                         "Activation."
273f4b65ab1SJennifer Lee                                         "Activations.Active")
2741abe55efSEd Tanous                                 {
275f4b65ab1SJennifer Lee                                     // The activation status of this software is
276f4b65ab1SJennifer Lee                                     // not currently active, so does not need to
277f4b65ab1SJennifer Lee                                     // be listed in the response
278c711bf86SEd Tanous                                     return;
279c711bf86SEd Tanous                                 }
280c711bf86SEd Tanous                                 nlohmann::json &members =
281c711bf86SEd Tanous                                     asyncResp->res.jsonValue["Members"];
282c711bf86SEd Tanous                                 members.push_back(
283f4b65ab1SJennifer Lee                                     {{"@odata.id", "/redfish/v1/UpdateService/"
2841abe55efSEd Tanous                                                    "FirmwareInventory/" +
285f4b65ab1SJennifer Lee                                                        swId}});
2861abe55efSEd Tanous                                 asyncResp->res
2871abe55efSEd Tanous                                     .jsonValue["Members@odata.count"] =
288c711bf86SEd Tanous                                     members.size();
2896c4eb9deSJennifer Lee                             },
2901abe55efSEd Tanous                             connectionName, obj.first,
2911abe55efSEd Tanous                             "org.freedesktop.DBus.Properties", "Get",
2921abe55efSEd Tanous                             "xyz.openbmc_project.Software.Activation",
293acb7cfb4SJennifer Lee                             "Activation");
2946c4eb9deSJennifer Lee                     }
2956c4eb9deSJennifer Lee                 }
296c711bf86SEd Tanous             },
297c711bf86SEd Tanous             "xyz.openbmc_project.ObjectMapper",
298c711bf86SEd Tanous             "/xyz/openbmc_project/object_mapper",
299c711bf86SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
300c711bf86SEd Tanous             "/xyz/openbmc_project/software", int32_t(1),
3011abe55efSEd Tanous             std::array<const char *, 1>{
3021abe55efSEd Tanous                 "xyz.openbmc_project.Software.Version"});
303729dae72SJennifer Lee     }
304729dae72SJennifer Lee };
305c711bf86SEd Tanous 
3061abe55efSEd Tanous class SoftwareInventory : public Node
3071abe55efSEd Tanous {
308729dae72SJennifer Lee   public:
309729dae72SJennifer Lee     template <typename CrowApp>
3101abe55efSEd Tanous     SoftwareInventory(CrowApp &app) :
3111abe55efSEd Tanous         Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
3121abe55efSEd Tanous              std::string())
3131abe55efSEd Tanous     {
314729dae72SJennifer Lee         entityPrivileges = {
315729dae72SJennifer Lee             {boost::beast::http::verb::get, {{"Login"}}},
316729dae72SJennifer Lee             {boost::beast::http::verb::head, {{"Login"}}},
317729dae72SJennifer Lee             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
318729dae72SJennifer Lee             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
319729dae72SJennifer Lee             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
320729dae72SJennifer Lee             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
321729dae72SJennifer Lee     }
322729dae72SJennifer Lee 
323729dae72SJennifer Lee   private:
324*87d84729SAndrew Geissler     /* Fill related item links (i.e. bmc, bios) in for inventory */
325*87d84729SAndrew Geissler     static void getRelatedItems(std::shared_ptr<AsyncResp> aResp,
326*87d84729SAndrew Geissler                                 const std::string &purpose)
327*87d84729SAndrew Geissler     {
328*87d84729SAndrew Geissler         if (purpose == fw_util::bmcPurpose)
329*87d84729SAndrew Geissler         {
330*87d84729SAndrew Geissler             nlohmann::json &members = aResp->res.jsonValue["RelatedItem"];
331*87d84729SAndrew Geissler             members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
332*87d84729SAndrew Geissler             aResp->res.jsonValue["Members@odata.count"] = members.size();
333*87d84729SAndrew Geissler         }
334*87d84729SAndrew Geissler         else if (purpose == fw_util::biosPurpose)
335*87d84729SAndrew Geissler         {
336*87d84729SAndrew Geissler             // TODO(geissonator) Need BIOS schema support added for this
337*87d84729SAndrew Geissler             //                   to be valid
338*87d84729SAndrew Geissler             // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"];
339*87d84729SAndrew Geissler             // members.push_back(
340*87d84729SAndrew Geissler             //    {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}});
341*87d84729SAndrew Geissler             // aResp->res.jsonValue["Members@odata.count"] = members.size();
342*87d84729SAndrew Geissler         }
343*87d84729SAndrew Geissler         else
344*87d84729SAndrew Geissler         {
345*87d84729SAndrew Geissler             BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
346*87d84729SAndrew Geissler         }
347*87d84729SAndrew Geissler     }
348*87d84729SAndrew Geissler 
34955c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
3501abe55efSEd Tanous                const std::vector<std::string> &params) override
3511abe55efSEd Tanous     {
352c711bf86SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3530f74e643SEd Tanous         res.jsonValue["@odata.type"] =
3540f74e643SEd Tanous             "#SoftwareInventory.v1_1_0.SoftwareInventory";
3550f74e643SEd Tanous         res.jsonValue["@odata.context"] =
3560f74e643SEd Tanous             "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
3570f74e643SEd Tanous         res.jsonValue["Name"] = "Software Inventory";
3580f74e643SEd Tanous         res.jsonValue["Updateable"] = false;
3590f74e643SEd Tanous         res.jsonValue["Status"]["Health"] = "OK";
3600f74e643SEd Tanous         res.jsonValue["Status"]["HealthRollup"] = "OK";
3610f74e643SEd Tanous         res.jsonValue["Status"]["State"] = "Enabled";
3626c4eb9deSJennifer Lee 
3631abe55efSEd Tanous         if (params.size() != 1)
3641abe55efSEd Tanous         {
365f12894f8SJason M. Bills             messages::internalError(res);
366729dae72SJennifer Lee             res.end();
367729dae72SJennifer Lee             return;
368729dae72SJennifer Lee         }
369729dae72SJennifer Lee 
3703ae837c9SEd Tanous         std::shared_ptr<std::string> swId =
371c711bf86SEd Tanous             std::make_shared<std::string>(params[0]);
372c711bf86SEd Tanous 
37355c7b7a2SEd Tanous         res.jsonValue["@odata.id"] =
3743ae837c9SEd Tanous             "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
375c711bf86SEd Tanous 
376c711bf86SEd Tanous         crow::connections::systemBus->async_method_call(
3773ae837c9SEd Tanous             [asyncResp, swId](
378c711bf86SEd Tanous                 const boost::system::error_code ec,
3796c4eb9deSJennifer Lee                 const std::vector<std::pair<
3801abe55efSEd Tanous                     std::string, std::vector<std::pair<
3811abe55efSEd Tanous                                      std::string, std::vector<std::string>>>>>
3826c4eb9deSJennifer Lee                     &subtree) {
38355c7b7a2SEd Tanous                 BMCWEB_LOG_DEBUG << "doGet callback...";
3841abe55efSEd Tanous                 if (ec)
3851abe55efSEd Tanous                 {
386f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
3876c4eb9deSJennifer Lee                     return;
3886c4eb9deSJennifer Lee                 }
3896c4eb9deSJennifer Lee 
3901abe55efSEd Tanous                 for (const std::pair<
3911abe55efSEd Tanous                          std::string,
3921abe55efSEd Tanous                          std::vector<
3931abe55efSEd Tanous                              std::pair<std::string, std::vector<std::string>>>>
3941abe55efSEd Tanous                          &obj : subtree)
3951abe55efSEd Tanous                 {
3963ae837c9SEd Tanous                     if (boost::ends_with(obj.first, *swId) != true)
3971abe55efSEd Tanous                     {
398acb7cfb4SJennifer Lee                         continue;
399acb7cfb4SJennifer Lee                     }
400acb7cfb4SJennifer Lee 
401f4b65ab1SJennifer Lee                     if (obj.second.size() < 1)
4021abe55efSEd Tanous                     {
403acb7cfb4SJennifer Lee                         continue;
404acb7cfb4SJennifer Lee                     }
4056c4eb9deSJennifer Lee 
40655c7b7a2SEd Tanous                     crow::connections::systemBus->async_method_call(
4071abe55efSEd Tanous                         [asyncResp,
4083ae837c9SEd Tanous                          swId](const boost::system::error_code error_code,
4091abe55efSEd Tanous                                const boost::container::flat_map<
4101abe55efSEd Tanous                                    std::string, VariantType> &propertiesList) {
4111abe55efSEd Tanous                             if (error_code)
4121abe55efSEd Tanous                             {
413f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
4146c4eb9deSJennifer Lee                                 return;
4156c4eb9deSJennifer Lee                             }
4161abe55efSEd Tanous                             boost::container::flat_map<
4171abe55efSEd Tanous                                 std::string, VariantType>::const_iterator it =
4186c4eb9deSJennifer Lee                                 propertiesList.find("Purpose");
4191abe55efSEd Tanous                             if (it == propertiesList.end())
4201abe55efSEd Tanous                             {
4211abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4221abe55efSEd Tanous                                     << "Can't find property \"Purpose\"!";
423f12894f8SJason M. Bills                                 messages::propertyMissing(asyncResp->res,
424f12894f8SJason M. Bills                                                           "Purpose");
4256c4eb9deSJennifer Lee                                 return;
4266c4eb9deSJennifer Lee                             }
4273ae837c9SEd Tanous                             const std::string *swInvPurpose =
428abf2add6SEd Tanous                                 std::get_if<std::string>(&it->second);
4293ae837c9SEd Tanous                             if (swInvPurpose == nullptr)
4301abe55efSEd Tanous                             {
4311abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4321abe55efSEd Tanous                                     << "wrong types for property\"Purpose\"!";
433f12894f8SJason M. Bills                                 messages::propertyValueTypeError(asyncResp->res,
434f12894f8SJason M. Bills                                                                  "", "Purpose");
435acb7cfb4SJennifer Lee                                 return;
436acb7cfb4SJennifer Lee                             }
437c711bf86SEd Tanous 
4383ae837c9SEd Tanous                             BMCWEB_LOG_DEBUG << "swInvPurpose = "
4393ae837c9SEd Tanous                                              << *swInvPurpose;
440c711bf86SEd Tanous                             it = propertiesList.find("Version");
4411abe55efSEd Tanous                             if (it == propertiesList.end())
4421abe55efSEd Tanous                             {
4431abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4441abe55efSEd Tanous                                     << "Can't find property \"Version\"!";
445f12894f8SJason M. Bills                                 messages::propertyMissing(asyncResp->res,
446f12894f8SJason M. Bills                                                           "Version");
447c711bf86SEd Tanous                                 return;
448acb7cfb4SJennifer Lee                             }
449acb7cfb4SJennifer Lee 
450f4b65ab1SJennifer Lee                             BMCWEB_LOG_DEBUG << "Version found!";
451c711bf86SEd Tanous 
452f4b65ab1SJennifer Lee                             const std::string *version =
453abf2add6SEd Tanous                                 std::get_if<std::string>(&it->second);
454f4b65ab1SJennifer Lee 
455f4b65ab1SJennifer Lee                             if (version == nullptr)
4561abe55efSEd Tanous                             {
4571abe55efSEd Tanous                                 BMCWEB_LOG_DEBUG
4581abe55efSEd Tanous                                     << "Can't find property \"Version\"!";
459f12894f8SJason M. Bills 
460f12894f8SJason M. Bills                                 messages::propertyValueTypeError(asyncResp->res,
461f12894f8SJason M. Bills                                                                  "", "Version");
4626c4eb9deSJennifer Lee                                 return;
4636c4eb9deSJennifer Lee                             }
464c711bf86SEd Tanous                             asyncResp->res.jsonValue["Version"] = *version;
4653ae837c9SEd Tanous                             asyncResp->res.jsonValue["Id"] = *swId;
46654daabe7SAndrew Geissler 
46754daabe7SAndrew Geissler                             // swInvPurpose is of format:
46854daabe7SAndrew Geissler                             // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
46954daabe7SAndrew Geissler                             // Translate this to "ABC update"
47054daabe7SAndrew Geissler                             size_t endDesc = swInvPurpose->rfind(".");
47154daabe7SAndrew Geissler                             if (endDesc == std::string::npos)
47254daabe7SAndrew Geissler                             {
47354daabe7SAndrew Geissler                                 messages::internalError(asyncResp->res);
47454daabe7SAndrew Geissler                                 return;
47554daabe7SAndrew Geissler                             }
47654daabe7SAndrew Geissler                             endDesc++;
47754daabe7SAndrew Geissler                             if (endDesc >= swInvPurpose->size())
47854daabe7SAndrew Geissler                             {
47954daabe7SAndrew Geissler                                 messages::internalError(asyncResp->res);
48054daabe7SAndrew Geissler                                 return;
48154daabe7SAndrew Geissler                             }
48254daabe7SAndrew Geissler 
48354daabe7SAndrew Geissler                             std::string formatDesc =
48454daabe7SAndrew Geissler                                 swInvPurpose->substr(endDesc);
48554daabe7SAndrew Geissler                             asyncResp->res.jsonValue["Description"] =
48654daabe7SAndrew Geissler                                 formatDesc + " update";
487*87d84729SAndrew Geissler                             getRelatedItems(asyncResp, *swInvPurpose);
4886c4eb9deSJennifer Lee                         },
489c711bf86SEd Tanous                         obj.second[0].first, obj.first,
490c711bf86SEd Tanous                         "org.freedesktop.DBus.Properties", "GetAll",
491c711bf86SEd Tanous                         "xyz.openbmc_project.Software.Version");
4926c4eb9deSJennifer Lee                 }
493c711bf86SEd Tanous             },
494c711bf86SEd Tanous             "xyz.openbmc_project.ObjectMapper",
495c711bf86SEd Tanous             "/xyz/openbmc_project/object_mapper",
496c711bf86SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
497c711bf86SEd Tanous             "/xyz/openbmc_project/software", int32_t(1),
4981abe55efSEd Tanous             std::array<const char *, 1>{
4991abe55efSEd Tanous                 "xyz.openbmc_project.Software.Version"});
5006c4eb9deSJennifer Lee     }
501729dae72SJennifer Lee };
502729dae72SJennifer Lee 
503729dae72SJennifer Lee } // namespace redfish
504