xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision eee0013e14f94300657c82019bd7d8cec7e2dbf8)
1*eee0013eSWilly Tu #pragma once
2*eee0013eSWilly Tu #include <async_resp.hpp>
3*eee0013eSWilly Tu #include <dbus_utility.hpp>
4*eee0013eSWilly Tu #include <sdbusplus/asio/property.hpp>
5*eee0013eSWilly Tu 
6*eee0013eSWilly Tu #include <algorithm>
7*eee0013eSWilly Tu #include <string>
8*eee0013eSWilly Tu #include <vector>
9*eee0013eSWilly Tu 
10*eee0013eSWilly Tu namespace redfish
11*eee0013eSWilly Tu {
12*eee0013eSWilly Tu namespace sw_util
13*eee0013eSWilly Tu {
14*eee0013eSWilly Tu /* @brief String that indicates a bios software instance */
15*eee0013eSWilly Tu constexpr const char* biosPurpose =
16*eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
17*eee0013eSWilly Tu 
18*eee0013eSWilly Tu /* @brief String that indicates a BMC software instance */
19*eee0013eSWilly Tu constexpr const char* bmcPurpose =
20*eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
21*eee0013eSWilly Tu 
22*eee0013eSWilly Tu /**
23*eee0013eSWilly Tu  * @brief Populate the running software version and image links
24*eee0013eSWilly Tu  *
25*eee0013eSWilly Tu  * @param[i,o] aResp             Async response object
26*eee0013eSWilly Tu  * @param[i]   swVersionPurpose  Indicates what target to look for
27*eee0013eSWilly Tu  * @param[i]   activeVersionPropName  Index in aResp->res.jsonValue to write
28*eee0013eSWilly Tu  * the running software version to
29*eee0013eSWilly Tu  * @param[i]   populateLinkToImages  Populate aResp->res "Links"
30*eee0013eSWilly Tu  * "ActiveSoftwareImage" with a link to the running software image and
31*eee0013eSWilly Tu  * "SoftwareImages" with a link to the all its software images
32*eee0013eSWilly Tu  *
33*eee0013eSWilly Tu  * @return void
34*eee0013eSWilly Tu  */
35*eee0013eSWilly Tu inline void
36*eee0013eSWilly Tu     populateSoftwareInformation(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
37*eee0013eSWilly Tu                                 const std::string& swVersionPurpose,
38*eee0013eSWilly Tu                                 const std::string& activeVersionPropName,
39*eee0013eSWilly Tu                                 const bool populateLinkToImages)
40*eee0013eSWilly Tu {
41*eee0013eSWilly Tu     // Used later to determine running (known on Redfish as active) Sw images
42*eee0013eSWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
43*eee0013eSWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
44*eee0013eSWilly Tu         "/xyz/openbmc_project/software/functional",
45*eee0013eSWilly Tu         "xyz.openbmc_project.Association", "endpoints",
46*eee0013eSWilly Tu         [aResp, swVersionPurpose, activeVersionPropName,
47*eee0013eSWilly Tu          populateLinkToImages](const boost::system::error_code ec,
48*eee0013eSWilly Tu                                const std::vector<std::string>& functionalSw) {
49*eee0013eSWilly Tu         BMCWEB_LOG_DEBUG << "populateSoftwareInformation enter";
50*eee0013eSWilly Tu         if (ec)
51*eee0013eSWilly Tu         {
52*eee0013eSWilly Tu             BMCWEB_LOG_ERROR << "error_code = " << ec;
53*eee0013eSWilly Tu             BMCWEB_LOG_ERROR << "error msg = " << ec.message();
54*eee0013eSWilly Tu             messages::internalError(aResp->res);
55*eee0013eSWilly Tu             return;
56*eee0013eSWilly Tu         }
57*eee0013eSWilly Tu 
58*eee0013eSWilly Tu         if (functionalSw.empty())
59*eee0013eSWilly Tu         {
60*eee0013eSWilly Tu             // Could keep going and try to populate SoftwareImages but
61*eee0013eSWilly Tu             // something is seriously wrong, so just fail
62*eee0013eSWilly Tu             BMCWEB_LOG_ERROR << "Zero functional software in system";
63*eee0013eSWilly Tu             messages::internalError(aResp->res);
64*eee0013eSWilly Tu             return;
65*eee0013eSWilly Tu         }
66*eee0013eSWilly Tu 
67*eee0013eSWilly Tu         std::vector<std::string> functionalSwIds;
68*eee0013eSWilly Tu         // example functionalSw:
69*eee0013eSWilly Tu         // v as 2 "/xyz/openbmc_project/software/ace821ef"
70*eee0013eSWilly Tu         //        "/xyz/openbmc_project/software/230fb078"
71*eee0013eSWilly Tu         for (const auto& sw : functionalSw)
72*eee0013eSWilly Tu         {
73*eee0013eSWilly Tu             sdbusplus::message::object_path path(sw);
74*eee0013eSWilly Tu             std::string leaf = path.filename();
75*eee0013eSWilly Tu             if (leaf.empty())
76*eee0013eSWilly Tu             {
77*eee0013eSWilly Tu                 continue;
78*eee0013eSWilly Tu             }
79*eee0013eSWilly Tu 
80*eee0013eSWilly Tu             functionalSwIds.push_back(leaf);
81*eee0013eSWilly Tu         }
82*eee0013eSWilly Tu 
83*eee0013eSWilly Tu         crow::connections::systemBus->async_method_call(
84*eee0013eSWilly Tu             [aResp, swVersionPurpose, activeVersionPropName,
85*eee0013eSWilly Tu              populateLinkToImages, functionalSwIds](
86*eee0013eSWilly Tu                 const boost::system::error_code ec2,
87*eee0013eSWilly Tu                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
88*eee0013eSWilly Tu             if (ec2)
89*eee0013eSWilly Tu             {
90*eee0013eSWilly Tu                 BMCWEB_LOG_ERROR << "error_code = " << ec2;
91*eee0013eSWilly Tu                 BMCWEB_LOG_ERROR << "error msg = " << ec2.message();
92*eee0013eSWilly Tu                 messages::internalError(aResp->res);
93*eee0013eSWilly Tu                 return;
94*eee0013eSWilly Tu             }
95*eee0013eSWilly Tu 
96*eee0013eSWilly Tu             BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " images";
97*eee0013eSWilly Tu 
98*eee0013eSWilly Tu             for (const std::pair<std::string,
99*eee0013eSWilly Tu                                  std::vector<std::pair<
100*eee0013eSWilly Tu                                      std::string, std::vector<std::string>>>>&
101*eee0013eSWilly Tu                      obj : subtree)
102*eee0013eSWilly Tu             {
103*eee0013eSWilly Tu 
104*eee0013eSWilly Tu                 sdbusplus::message::object_path path(obj.first);
105*eee0013eSWilly Tu                 std::string swId = path.filename();
106*eee0013eSWilly Tu                 if (swId.empty())
107*eee0013eSWilly Tu                 {
108*eee0013eSWilly Tu                     messages::internalError(aResp->res);
109*eee0013eSWilly Tu                     BMCWEB_LOG_ERROR << "Invalid software ID";
110*eee0013eSWilly Tu 
111*eee0013eSWilly Tu                     return;
112*eee0013eSWilly Tu                 }
113*eee0013eSWilly Tu 
114*eee0013eSWilly Tu                 bool runningImage = false;
115*eee0013eSWilly Tu                 // Look at Ids from
116*eee0013eSWilly Tu                 // /xyz/openbmc_project/software/functional
117*eee0013eSWilly Tu                 // to determine if this is a running image
118*eee0013eSWilly Tu                 if (std::find(functionalSwIds.begin(), functionalSwIds.end(),
119*eee0013eSWilly Tu                               swId) != functionalSwIds.end())
120*eee0013eSWilly Tu                 {
121*eee0013eSWilly Tu                     runningImage = true;
122*eee0013eSWilly Tu                 }
123*eee0013eSWilly Tu 
124*eee0013eSWilly Tu                 // Now grab its version info
125*eee0013eSWilly Tu                 crow::connections::systemBus->async_method_call(
126*eee0013eSWilly Tu                     [aResp, swId, runningImage, swVersionPurpose,
127*eee0013eSWilly Tu                      activeVersionPropName, populateLinkToImages](
128*eee0013eSWilly Tu                         const boost::system::error_code ec3,
129*eee0013eSWilly Tu                         const dbus::utility::DBusPropertiesMap&
130*eee0013eSWilly Tu                             propertiesList) {
131*eee0013eSWilly Tu                     if (ec3)
132*eee0013eSWilly Tu                     {
133*eee0013eSWilly Tu                         BMCWEB_LOG_ERROR << "error_code = " << ec3;
134*eee0013eSWilly Tu                         BMCWEB_LOG_ERROR << "error msg = " << ec3.message();
135*eee0013eSWilly Tu                         // Have seen the code update app delete the D-Bus
136*eee0013eSWilly Tu                         // object, during code update, between the call to
137*eee0013eSWilly Tu                         // mapper and here. Just leave these properties off if
138*eee0013eSWilly Tu                         // resource not found.
139*eee0013eSWilly Tu                         if (ec3.value() == EBADR)
140*eee0013eSWilly Tu                         {
141*eee0013eSWilly Tu                             return;
142*eee0013eSWilly Tu                         }
143*eee0013eSWilly Tu                         messages::internalError(aResp->res);
144*eee0013eSWilly Tu                         return;
145*eee0013eSWilly Tu                     }
146*eee0013eSWilly Tu                     // example propertiesList
147*eee0013eSWilly Tu                     // a{sv} 2 "Version" s
148*eee0013eSWilly Tu                     // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
149*eee0013eSWilly Tu                     // s
150*eee0013eSWilly Tu                     // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
151*eee0013eSWilly Tu                     std::string version;
152*eee0013eSWilly Tu                     std::string swInvPurpose;
153*eee0013eSWilly Tu                     for (const auto& propertyPair : propertiesList)
154*eee0013eSWilly Tu                     {
155*eee0013eSWilly Tu                         if (propertyPair.first == "Purpose")
156*eee0013eSWilly Tu                         {
157*eee0013eSWilly Tu                             const std::string* purpose =
158*eee0013eSWilly Tu                                 std::get_if<std::string>(&propertyPair.second);
159*eee0013eSWilly Tu                             if (purpose == nullptr)
160*eee0013eSWilly Tu                             {
161*eee0013eSWilly Tu                                 messages::internalError(aResp->res);
162*eee0013eSWilly Tu                                 return;
163*eee0013eSWilly Tu                             }
164*eee0013eSWilly Tu                             swInvPurpose = *purpose;
165*eee0013eSWilly Tu                         }
166*eee0013eSWilly Tu                         if (propertyPair.first == "Version")
167*eee0013eSWilly Tu                         {
168*eee0013eSWilly Tu                             const std::string* versionPtr =
169*eee0013eSWilly Tu                                 std::get_if<std::string>(&propertyPair.second);
170*eee0013eSWilly Tu                             if (versionPtr == nullptr)
171*eee0013eSWilly Tu                             {
172*eee0013eSWilly Tu                                 messages::internalError(aResp->res);
173*eee0013eSWilly Tu                                 return;
174*eee0013eSWilly Tu                             }
175*eee0013eSWilly Tu                             version = *versionPtr;
176*eee0013eSWilly Tu                         }
177*eee0013eSWilly Tu                     }
178*eee0013eSWilly Tu 
179*eee0013eSWilly Tu                     BMCWEB_LOG_DEBUG << "Image ID: " << swId;
180*eee0013eSWilly Tu                     BMCWEB_LOG_DEBUG << "Image purpose: " << swInvPurpose;
181*eee0013eSWilly Tu                     BMCWEB_LOG_DEBUG << "Running image: " << runningImage;
182*eee0013eSWilly Tu 
183*eee0013eSWilly Tu                     if (version.empty())
184*eee0013eSWilly Tu                     {
185*eee0013eSWilly Tu                         messages::internalError(aResp->res);
186*eee0013eSWilly Tu                         return;
187*eee0013eSWilly Tu                     }
188*eee0013eSWilly Tu                     if (swInvPurpose != swVersionPurpose)
189*eee0013eSWilly Tu                     {
190*eee0013eSWilly Tu                         // Not purpose we're looking for
191*eee0013eSWilly Tu                         return;
192*eee0013eSWilly Tu                     }
193*eee0013eSWilly Tu 
194*eee0013eSWilly Tu                     if (populateLinkToImages)
195*eee0013eSWilly Tu                     {
196*eee0013eSWilly Tu                         nlohmann::json& softwareImageMembers =
197*eee0013eSWilly Tu                             aResp->res.jsonValue["Links"]["SoftwareImages"];
198*eee0013eSWilly Tu                         // Firmware images are at
199*eee0013eSWilly Tu                         // /redfish/v1/UpdateService/FirmwareInventory/<Id>
200*eee0013eSWilly Tu                         // e.g. .../FirmwareInventory/82d3ec86
201*eee0013eSWilly Tu                         softwareImageMembers.push_back(
202*eee0013eSWilly Tu                             {{"@odata.id", "/redfish/v1/UpdateService/"
203*eee0013eSWilly Tu                                            "FirmwareInventory/" +
204*eee0013eSWilly Tu                                                swId}});
205*eee0013eSWilly Tu                         aResp->res
206*eee0013eSWilly Tu                             .jsonValue["Links"]["SoftwareImages@odata.count"] =
207*eee0013eSWilly Tu                             softwareImageMembers.size();
208*eee0013eSWilly Tu 
209*eee0013eSWilly Tu                         if (runningImage)
210*eee0013eSWilly Tu                         {
211*eee0013eSWilly Tu                             // Create the link to the running image
212*eee0013eSWilly Tu                             aResp->res
213*eee0013eSWilly Tu                                 .jsonValue["Links"]["ActiveSoftwareImage"] = {
214*eee0013eSWilly Tu                                 {"@odata.id", "/redfish/v1/UpdateService/"
215*eee0013eSWilly Tu                                               "FirmwareInventory/" +
216*eee0013eSWilly Tu                                                   swId}};
217*eee0013eSWilly Tu                         }
218*eee0013eSWilly Tu                     }
219*eee0013eSWilly Tu                     if (!activeVersionPropName.empty() && runningImage)
220*eee0013eSWilly Tu                     {
221*eee0013eSWilly Tu                         aResp->res.jsonValue[activeVersionPropName] = version;
222*eee0013eSWilly Tu                     }
223*eee0013eSWilly Tu                     },
224*eee0013eSWilly Tu                     obj.second[0].first, obj.first,
225*eee0013eSWilly Tu                     "org.freedesktop.DBus.Properties", "GetAll",
226*eee0013eSWilly Tu                     "xyz.openbmc_project.Software.Version");
227*eee0013eSWilly Tu             }
228*eee0013eSWilly Tu             },
229*eee0013eSWilly Tu             "xyz.openbmc_project.ObjectMapper",
230*eee0013eSWilly Tu             "/xyz/openbmc_project/object_mapper",
231*eee0013eSWilly Tu             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
232*eee0013eSWilly Tu             "/xyz/openbmc_project/software", static_cast<int32_t>(0),
233*eee0013eSWilly Tu             std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
234*eee0013eSWilly Tu         });
235*eee0013eSWilly Tu }
236*eee0013eSWilly Tu 
237*eee0013eSWilly Tu /**
238*eee0013eSWilly Tu  * @brief Translate input swState to Redfish state
239*eee0013eSWilly Tu  *
240*eee0013eSWilly Tu  * This function will return the corresponding Redfish state
241*eee0013eSWilly Tu  *
242*eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
243*eee0013eSWilly Tu  *
244*eee0013eSWilly Tu  * @return The corresponding Redfish state
245*eee0013eSWilly Tu  */
246*eee0013eSWilly Tu inline std::string getRedfishSwState(const std::string& swState)
247*eee0013eSWilly Tu {
248*eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active")
249*eee0013eSWilly Tu     {
250*eee0013eSWilly Tu         return "Enabled";
251*eee0013eSWilly Tu     }
252*eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
253*eee0013eSWilly Tu                    "Activations.Activating")
254*eee0013eSWilly Tu     {
255*eee0013eSWilly Tu         return "Updating";
256*eee0013eSWilly Tu     }
257*eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
258*eee0013eSWilly Tu                    "Activations.StandbySpare")
259*eee0013eSWilly Tu     {
260*eee0013eSWilly Tu         return "StandbySpare";
261*eee0013eSWilly Tu     }
262*eee0013eSWilly Tu     BMCWEB_LOG_DEBUG << "Default sw state " << swState << " to Disabled";
263*eee0013eSWilly Tu     return "Disabled";
264*eee0013eSWilly Tu }
265*eee0013eSWilly Tu 
266*eee0013eSWilly Tu /**
267*eee0013eSWilly Tu  * @brief Translate input swState to Redfish health state
268*eee0013eSWilly Tu  *
269*eee0013eSWilly Tu  * This function will return the corresponding Redfish health state
270*eee0013eSWilly Tu  *
271*eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
272*eee0013eSWilly Tu  *
273*eee0013eSWilly Tu  * @return The corresponding Redfish health state
274*eee0013eSWilly Tu  */
275*eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState)
276*eee0013eSWilly Tu {
277*eee0013eSWilly Tu     if ((swState ==
278*eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Active") ||
279*eee0013eSWilly Tu         (swState == "xyz.openbmc_project.Software.Activation.Activations."
280*eee0013eSWilly Tu                     "Activating") ||
281*eee0013eSWilly Tu         (swState ==
282*eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Ready"))
283*eee0013eSWilly Tu     {
284*eee0013eSWilly Tu         return "OK";
285*eee0013eSWilly Tu     }
286*eee0013eSWilly Tu     BMCWEB_LOG_DEBUG << "Sw state " << swState << " to Warning";
287*eee0013eSWilly Tu     return "Warning";
288*eee0013eSWilly Tu }
289*eee0013eSWilly Tu 
290*eee0013eSWilly Tu /**
291*eee0013eSWilly Tu  * @brief Put status of input swId into json response
292*eee0013eSWilly Tu  *
293*eee0013eSWilly Tu  * This function will put the appropriate Redfish state of the input
294*eee0013eSWilly Tu  * software id to ["Status"]["State"] within the json response
295*eee0013eSWilly Tu  *
296*eee0013eSWilly Tu  * @param[i,o] aResp    Async response object
297*eee0013eSWilly Tu  * @param[i]   swId     The software ID to get status for
298*eee0013eSWilly Tu  * @param[i]   dbusSvc  The dbus service implementing the software object
299*eee0013eSWilly Tu  *
300*eee0013eSWilly Tu  * @return void
301*eee0013eSWilly Tu  */
302*eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
303*eee0013eSWilly Tu                         const std::shared_ptr<std::string>& swId,
304*eee0013eSWilly Tu                         const std::string& dbusSvc)
305*eee0013eSWilly Tu {
306*eee0013eSWilly Tu     BMCWEB_LOG_DEBUG << "getSwStatus: swId " << *swId << " svc " << dbusSvc;
307*eee0013eSWilly Tu 
308*eee0013eSWilly Tu     crow::connections::systemBus->async_method_call(
309*eee0013eSWilly Tu         [asyncResp,
310*eee0013eSWilly Tu          swId](const boost::system::error_code errorCode,
311*eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
312*eee0013eSWilly Tu         if (errorCode)
313*eee0013eSWilly Tu         {
314*eee0013eSWilly Tu             // not all swtypes are updateable, this is ok
315*eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
316*eee0013eSWilly Tu             return;
317*eee0013eSWilly Tu         }
318*eee0013eSWilly Tu         const std::string* swInvActivation = nullptr;
319*eee0013eSWilly Tu         for (const auto& property : propertiesList)
320*eee0013eSWilly Tu         {
321*eee0013eSWilly Tu             if (property.first == "Activation")
322*eee0013eSWilly Tu             {
323*eee0013eSWilly Tu                 swInvActivation = std::get_if<std::string>(&property.second);
324*eee0013eSWilly Tu             }
325*eee0013eSWilly Tu         }
326*eee0013eSWilly Tu 
327*eee0013eSWilly Tu         if (swInvActivation == nullptr)
328*eee0013eSWilly Tu         {
329*eee0013eSWilly Tu             BMCWEB_LOG_DEBUG << "wrong types for property\"Activation\"!";
330*eee0013eSWilly Tu             messages::internalError(asyncResp->res);
331*eee0013eSWilly Tu             return;
332*eee0013eSWilly Tu         }
333*eee0013eSWilly Tu         BMCWEB_LOG_DEBUG << "getSwStatus: Activation " << *swInvActivation;
334*eee0013eSWilly Tu         asyncResp->res.jsonValue["Status"]["State"] =
335*eee0013eSWilly Tu             getRedfishSwState(*swInvActivation);
336*eee0013eSWilly Tu         asyncResp->res.jsonValue["Status"]["Health"] =
337*eee0013eSWilly Tu             getRedfishSwHealth(*swInvActivation);
338*eee0013eSWilly Tu         },
339*eee0013eSWilly Tu         dbusSvc, "/xyz/openbmc_project/software/" + *swId,
340*eee0013eSWilly Tu         "org.freedesktop.DBus.Properties", "GetAll",
341*eee0013eSWilly Tu         "xyz.openbmc_project.Software.Activation");
342*eee0013eSWilly Tu }
343*eee0013eSWilly Tu 
344*eee0013eSWilly Tu /**
345*eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
346*eee0013eSWilly Tu  *
347*eee0013eSWilly Tu  * This function checks whether software inventory component
348*eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
349*eee0013eSWilly Tu  * Property.
350*eee0013eSWilly Tu  *
351*eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
352*eee0013eSWilly Tu  * @param[i]   swId       The software ID
353*eee0013eSWilly Tu  */
354*eee0013eSWilly Tu inline void
355*eee0013eSWilly Tu     getSwUpdatableStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
356*eee0013eSWilly Tu                          const std::shared_ptr<std::string>& swId)
357*eee0013eSWilly Tu {
358*eee0013eSWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
359*eee0013eSWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
360*eee0013eSWilly Tu         "/xyz/openbmc_project/software/updateable",
361*eee0013eSWilly Tu         "xyz.openbmc_project.Association", "endpoints",
362*eee0013eSWilly Tu         [asyncResp, swId](const boost::system::error_code ec,
363*eee0013eSWilly Tu                           const std::vector<std::string>& objPaths) {
364*eee0013eSWilly Tu         if (ec)
365*eee0013eSWilly Tu         {
366*eee0013eSWilly Tu             BMCWEB_LOG_DEBUG << " error_code = " << ec
367*eee0013eSWilly Tu                              << " error msg =  " << ec.message();
368*eee0013eSWilly Tu             // System can exist with no updateable software,
369*eee0013eSWilly Tu             // so don't throw error here.
370*eee0013eSWilly Tu             return;
371*eee0013eSWilly Tu         }
372*eee0013eSWilly Tu         std::string reqSwObjPath = "/xyz/openbmc_project/software/" + *swId;
373*eee0013eSWilly Tu 
374*eee0013eSWilly Tu         if (std::find(objPaths.begin(), objPaths.end(), reqSwObjPath) !=
375*eee0013eSWilly Tu             objPaths.end())
376*eee0013eSWilly Tu         {
377*eee0013eSWilly Tu             asyncResp->res.jsonValue["Updatable"] = true;
378*eee0013eSWilly Tu             return;
379*eee0013eSWilly Tu         }
380*eee0013eSWilly Tu         });
381*eee0013eSWilly Tu }
382*eee0013eSWilly Tu 
383*eee0013eSWilly Tu } // namespace sw_util
384*eee0013eSWilly Tu } // namespace redfish
385