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