xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision 7f23576aa57522bbc6d123766d643ca374e9d525)
1eee0013eSWilly Tu #pragma once
23ccb3adbSEd Tanous #include "async_resp.hpp"
33ccb3adbSEd Tanous #include "dbus_utility.hpp"
43ccb3adbSEd Tanous #include "error_messages.hpp"
53ccb3adbSEd Tanous #include "generated/enums/resource.hpp"
6eddfc437SWilly Tu #include "http/utility.hpp"
73ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
83ccb3adbSEd Tanous 
9e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
10ef4c65b7SEd Tanous #include <boost/url/format.hpp>
11eee0013eSWilly Tu #include <sdbusplus/asio/property.hpp>
12d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
13eee0013eSWilly Tu 
14eee0013eSWilly Tu #include <algorithm>
15e99073f5SGeorge Liu #include <array>
16*7f23576aSJagpal Singh Gill #include <optional>
173544d2a7SEd Tanous #include <ranges>
18eee0013eSWilly Tu #include <string>
19e99073f5SGeorge Liu #include <string_view>
20eee0013eSWilly Tu #include <vector>
21eee0013eSWilly Tu 
22eee0013eSWilly Tu namespace redfish
23eee0013eSWilly Tu {
24eee0013eSWilly Tu namespace sw_util
25eee0013eSWilly Tu {
26eee0013eSWilly Tu /* @brief String that indicates a bios software instance */
27eee0013eSWilly Tu constexpr const char* biosPurpose =
28eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
29eee0013eSWilly Tu 
30eee0013eSWilly Tu /* @brief String that indicates a BMC software instance */
31eee0013eSWilly Tu constexpr const char* bmcPurpose =
32eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
33eee0013eSWilly Tu 
34*7f23576aSJagpal Singh Gill inline std::optional<sdbusplus::message::object_path>
35*7f23576aSJagpal Singh Gill     getFunctionalSoftwarePath(const std::string& swType)
36*7f23576aSJagpal Singh Gill {
37*7f23576aSJagpal Singh Gill     if (swType == bmcPurpose)
38*7f23576aSJagpal Singh Gill     {
39*7f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
40*7f23576aSJagpal Singh Gill         {
41*7f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
42*7f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bmc/functional");
43*7f23576aSJagpal Singh Gill         }
44*7f23576aSJagpal Singh Gill         else
45*7f23576aSJagpal Singh Gill         {
46*7f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
47*7f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
48*7f23576aSJagpal Singh Gill         }
49*7f23576aSJagpal Singh Gill     }
50*7f23576aSJagpal Singh Gill     else if (swType == biosPurpose)
51*7f23576aSJagpal Singh Gill     {
52*7f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
53*7f23576aSJagpal Singh Gill         {
54*7f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
55*7f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bios/functional");
56*7f23576aSJagpal Singh Gill         }
57*7f23576aSJagpal Singh Gill         else
58*7f23576aSJagpal Singh Gill         {
59*7f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
60*7f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
61*7f23576aSJagpal Singh Gill         }
62*7f23576aSJagpal Singh Gill     }
63*7f23576aSJagpal Singh Gill     else
64*7f23576aSJagpal Singh Gill     {
65*7f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("No valid software path");
66*7f23576aSJagpal Singh Gill         return std::nullopt;
67*7f23576aSJagpal Singh Gill     }
68*7f23576aSJagpal Singh Gill }
69*7f23576aSJagpal Singh Gill 
70eee0013eSWilly Tu /**
71eee0013eSWilly Tu  * @brief Populate the running software version and image links
72eee0013eSWilly Tu  *
73ac106bf6SEd Tanous  * @param[i,o] asyncResp             Async response object
74eee0013eSWilly Tu  * @param[i]   swVersionPurpose  Indicates what target to look for
75ac106bf6SEd Tanous  * @param[i]   activeVersionPropName  Index in asyncResp->res.jsonValue to write
76eee0013eSWilly Tu  * the running software version to
77ac106bf6SEd Tanous  * @param[i]   populateLinkToImages  Populate asyncResp->res "Links"
78eee0013eSWilly Tu  * "ActiveSoftwareImage" with a link to the running software image and
79eee0013eSWilly Tu  * "SoftwareImages" with a link to the all its software images
80eee0013eSWilly Tu  *
81eee0013eSWilly Tu  * @return void
82eee0013eSWilly Tu  */
83ac106bf6SEd Tanous inline void populateSoftwareInformation(
84ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
85eee0013eSWilly Tu     const std::string& swVersionPurpose,
86ac106bf6SEd Tanous     const std::string& activeVersionPropName, const bool populateLinkToImages)
87eee0013eSWilly Tu {
88*7f23576aSJagpal Singh Gill     auto swPath = getFunctionalSoftwarePath(swVersionPurpose);
89*7f23576aSJagpal Singh Gill     if (!swPath)
90*7f23576aSJagpal Singh Gill     {
91*7f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("Invalid software type");
92*7f23576aSJagpal Singh Gill         messages::internalError(asyncResp->res);
93*7f23576aSJagpal Singh Gill         return;
94*7f23576aSJagpal Singh Gill     }
95eee0013eSWilly Tu     // Used later to determine running (known on Redfish as active) Sw images
96a4eb761aSGeorge Liu     dbus::utility::getAssociationEndPoints(
97*7f23576aSJagpal Singh Gill         swPath.value().str,
98ac106bf6SEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
99ac106bf6SEd Tanous          populateLinkToImages](
100a4eb761aSGeorge Liu             const boost::system::error_code& ec,
101a4eb761aSGeorge Liu             const dbus::utility::MapperEndPoints& functionalSw) {
10262598e31SEd Tanous         BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
103eee0013eSWilly Tu         if (ec)
104eee0013eSWilly Tu         {
10562598e31SEd Tanous             BMCWEB_LOG_ERROR("error_code = {}", ec);
10662598e31SEd Tanous             BMCWEB_LOG_ERROR("error msg = {}", ec.message());
107ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
108eee0013eSWilly Tu             return;
109eee0013eSWilly Tu         }
110eee0013eSWilly Tu 
111eee0013eSWilly Tu         if (functionalSw.empty())
112eee0013eSWilly Tu         {
113eee0013eSWilly Tu             // Could keep going and try to populate SoftwareImages but
114eee0013eSWilly Tu             // something is seriously wrong, so just fail
11562598e31SEd Tanous             BMCWEB_LOG_ERROR("Zero functional software in system");
116ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
117eee0013eSWilly Tu             return;
118eee0013eSWilly Tu         }
119eee0013eSWilly Tu 
120eee0013eSWilly Tu         std::vector<std::string> functionalSwIds;
121eee0013eSWilly Tu         // example functionalSw:
122eee0013eSWilly Tu         // v as 2 "/xyz/openbmc_project/software/ace821ef"
123eee0013eSWilly Tu         //        "/xyz/openbmc_project/software/230fb078"
124c6830d5fSGunnar Mills         for (const auto& sw : functionalSw)
125eee0013eSWilly Tu         {
126c6830d5fSGunnar Mills             sdbusplus::message::object_path path(sw);
127eee0013eSWilly Tu             std::string leaf = path.filename();
128eee0013eSWilly Tu             if (leaf.empty())
129eee0013eSWilly Tu             {
130eee0013eSWilly Tu                 continue;
131eee0013eSWilly Tu             }
132eee0013eSWilly Tu 
133eee0013eSWilly Tu             functionalSwIds.push_back(leaf);
134eee0013eSWilly Tu         }
135eee0013eSWilly Tu 
136e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> interfaces = {
137e99073f5SGeorge Liu             "xyz.openbmc_project.Software.Version"};
138e99073f5SGeorge Liu         dbus::utility::getSubTree(
139e99073f5SGeorge Liu             "/xyz/openbmc_project/software", 0, interfaces,
140ac106bf6SEd Tanous             [asyncResp, swVersionPurpose, activeVersionPropName,
141eee0013eSWilly Tu              populateLinkToImages, functionalSwIds](
142e99073f5SGeorge Liu                 const boost::system::error_code& ec2,
143eee0013eSWilly Tu                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
144eee0013eSWilly Tu             if (ec2)
145eee0013eSWilly Tu             {
14662598e31SEd Tanous                 BMCWEB_LOG_ERROR("error_code = {}", ec2);
14762598e31SEd Tanous                 BMCWEB_LOG_ERROR("error msg = {}", ec2.message());
148ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
149eee0013eSWilly Tu                 return;
150eee0013eSWilly Tu             }
151eee0013eSWilly Tu 
15262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
153eee0013eSWilly Tu 
154eee0013eSWilly Tu             for (const std::pair<std::string,
155eee0013eSWilly Tu                                  std::vector<std::pair<
156eee0013eSWilly Tu                                      std::string, std::vector<std::string>>>>&
157eee0013eSWilly Tu                      obj : subtree)
158eee0013eSWilly Tu             {
159eee0013eSWilly Tu                 sdbusplus::message::object_path path(obj.first);
160eee0013eSWilly Tu                 std::string swId = path.filename();
161eee0013eSWilly Tu                 if (swId.empty())
162eee0013eSWilly Tu                 {
163ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
16462598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid software ID");
165eee0013eSWilly Tu 
166eee0013eSWilly Tu                     return;
167eee0013eSWilly Tu                 }
168eee0013eSWilly Tu 
169eee0013eSWilly Tu                 bool runningImage = false;
170eee0013eSWilly Tu                 // Look at Ids from
171eee0013eSWilly Tu                 // /xyz/openbmc_project/software/functional
172eee0013eSWilly Tu                 // to determine if this is a running image
1733544d2a7SEd Tanous                 if (std::ranges::find(functionalSwIds, swId) !=
1743544d2a7SEd Tanous                     functionalSwIds.end())
175eee0013eSWilly Tu                 {
176eee0013eSWilly Tu                     runningImage = true;
177eee0013eSWilly Tu                 }
178eee0013eSWilly Tu 
179eee0013eSWilly Tu                 // Now grab its version info
180d1bde9e5SKrzysztof Grobelny                 sdbusplus::asio::getAllProperties(
181d1bde9e5SKrzysztof Grobelny                     *crow::connections::systemBus, obj.second[0].first,
182d1bde9e5SKrzysztof Grobelny                     obj.first, "xyz.openbmc_project.Software.Version",
183ac106bf6SEd Tanous                     [asyncResp, swId, runningImage, swVersionPurpose,
184eee0013eSWilly Tu                      activeVersionPropName, populateLinkToImages](
1855e7e2dc5SEd Tanous                         const boost::system::error_code& ec3,
186eee0013eSWilly Tu                         const dbus::utility::DBusPropertiesMap&
187eee0013eSWilly Tu                             propertiesList) {
188eee0013eSWilly Tu                     if (ec3)
189eee0013eSWilly Tu                     {
19062598e31SEd Tanous                         BMCWEB_LOG_ERROR("error_code = {}", ec3);
19162598e31SEd Tanous                         BMCWEB_LOG_ERROR("error msg = {}", ec3.message());
192eee0013eSWilly Tu                         // Have seen the code update app delete the D-Bus
193eee0013eSWilly Tu                         // object, during code update, between the call to
194eee0013eSWilly Tu                         // mapper and here. Just leave these properties off if
195eee0013eSWilly Tu                         // resource not found.
196eee0013eSWilly Tu                         if (ec3.value() == EBADR)
197eee0013eSWilly Tu                         {
198eee0013eSWilly Tu                             return;
199eee0013eSWilly Tu                         }
200ac106bf6SEd Tanous                         messages::internalError(asyncResp->res);
201eee0013eSWilly Tu                         return;
202eee0013eSWilly Tu                     }
203eee0013eSWilly Tu                     // example propertiesList
204eee0013eSWilly Tu                     // a{sv} 2 "Version" s
205eee0013eSWilly Tu                     // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
206eee0013eSWilly Tu                     // s
207eee0013eSWilly Tu                     // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
208d1bde9e5SKrzysztof Grobelny                     const std::string* version = nullptr;
209d1bde9e5SKrzysztof Grobelny                     const std::string* swInvPurpose = nullptr;
210d1bde9e5SKrzysztof Grobelny 
211d1bde9e5SKrzysztof Grobelny                     const bool success = sdbusplus::unpackPropertiesNoThrow(
212d1bde9e5SKrzysztof Grobelny                         dbus_utils::UnpackErrorPrinter(), propertiesList,
213d1bde9e5SKrzysztof Grobelny                         "Purpose", swInvPurpose, "Version", version);
214d1bde9e5SKrzysztof Grobelny 
215d1bde9e5SKrzysztof Grobelny                     if (!success)
216eee0013eSWilly Tu                     {
217ac106bf6SEd Tanous                         messages::internalError(asyncResp->res);
218eee0013eSWilly Tu                         return;
219eee0013eSWilly Tu                     }
220eee0013eSWilly Tu 
221d1bde9e5SKrzysztof Grobelny                     if (version == nullptr || version->empty())
222eee0013eSWilly Tu                     {
223ac106bf6SEd Tanous                         messages::internalError(asyncResp->res);
224eee0013eSWilly Tu                         return;
225eee0013eSWilly Tu                     }
226d1bde9e5SKrzysztof Grobelny                     if (swInvPurpose == nullptr ||
227d1bde9e5SKrzysztof Grobelny                         *swInvPurpose != swVersionPurpose)
228eee0013eSWilly Tu                     {
229eee0013eSWilly Tu                         // Not purpose we're looking for
230eee0013eSWilly Tu                         return;
231eee0013eSWilly Tu                     }
232eee0013eSWilly Tu 
23362598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Image ID: {}", swId);
23462598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Running image: {}", runningImage);
23562598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose);
236d1bde9e5SKrzysztof Grobelny 
237eee0013eSWilly Tu                     if (populateLinkToImages)
238eee0013eSWilly Tu                     {
239eee0013eSWilly Tu                         nlohmann::json& softwareImageMembers =
240ac106bf6SEd Tanous                             asyncResp->res.jsonValue["Links"]["SoftwareImages"];
241eee0013eSWilly Tu                         // Firmware images are at
242eee0013eSWilly Tu                         // /redfish/v1/UpdateService/FirmwareInventory/<Id>
243eee0013eSWilly Tu                         // e.g. .../FirmwareInventory/82d3ec86
244613dabeaSEd Tanous                         nlohmann::json::object_t member;
245ef4c65b7SEd Tanous                         member["@odata.id"] = boost::urls::format(
246ef4c65b7SEd Tanous                             "/redfish/v1/UpdateService/FirmwareInventory/{}",
247ef4c65b7SEd Tanous                             swId);
248b2ba3072SPatrick Williams                         softwareImageMembers.emplace_back(std::move(member));
249ac106bf6SEd Tanous                         asyncResp->res
250eee0013eSWilly Tu                             .jsonValue["Links"]["SoftwareImages@odata.count"] =
251eee0013eSWilly Tu                             softwareImageMembers.size();
252eee0013eSWilly Tu 
253eee0013eSWilly Tu                         if (runningImage)
254eee0013eSWilly Tu                         {
255613dabeaSEd Tanous                             nlohmann::json::object_t runningMember;
256ef4c65b7SEd Tanous                             runningMember["@odata.id"] = boost::urls::format(
257ef4c65b7SEd Tanous                                 "/redfish/v1/UpdateService/FirmwareInventory/{}",
258ef4c65b7SEd Tanous                                 swId);
259eee0013eSWilly Tu                             // Create the link to the running image
260ac106bf6SEd Tanous                             asyncResp->res
261613dabeaSEd Tanous                                 .jsonValue["Links"]["ActiveSoftwareImage"] =
262613dabeaSEd Tanous                                 std::move(runningMember);
263eee0013eSWilly Tu                         }
264eee0013eSWilly Tu                     }
265eee0013eSWilly Tu                     if (!activeVersionPropName.empty() && runningImage)
266eee0013eSWilly Tu                     {
267ac106bf6SEd Tanous                         asyncResp->res.jsonValue[activeVersionPropName] =
268ac106bf6SEd Tanous                             *version;
269eee0013eSWilly Tu                     }
270d1bde9e5SKrzysztof Grobelny                 });
271eee0013eSWilly Tu             }
272e99073f5SGeorge Liu         });
273eee0013eSWilly Tu     });
274eee0013eSWilly Tu }
275eee0013eSWilly Tu 
276eee0013eSWilly Tu /**
277eee0013eSWilly Tu  * @brief Translate input swState to Redfish state
278eee0013eSWilly Tu  *
279eee0013eSWilly Tu  * This function will return the corresponding Redfish state
280eee0013eSWilly Tu  *
281eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
282eee0013eSWilly Tu  *
283eee0013eSWilly Tu  * @return The corresponding Redfish state
284eee0013eSWilly Tu  */
2850ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState)
286eee0013eSWilly Tu {
287eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active")
288eee0013eSWilly Tu     {
2890ec8b83dSEd Tanous         return resource::State::Enabled;
290eee0013eSWilly Tu     }
291eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
292eee0013eSWilly Tu                    "Activations.Activating")
293eee0013eSWilly Tu     {
2940ec8b83dSEd Tanous         return resource::State::Updating;
295eee0013eSWilly Tu     }
296eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
297eee0013eSWilly Tu                    "Activations.StandbySpare")
298eee0013eSWilly Tu     {
2990ec8b83dSEd Tanous         return resource::State::StandbySpare;
300eee0013eSWilly Tu     }
30162598e31SEd Tanous     BMCWEB_LOG_DEBUG("Default sw state {} to Disabled", swState);
3020ec8b83dSEd Tanous     return resource::State::Disabled;
303eee0013eSWilly Tu }
304eee0013eSWilly Tu 
305eee0013eSWilly Tu /**
306eee0013eSWilly Tu  * @brief Translate input swState to Redfish health state
307eee0013eSWilly Tu  *
308eee0013eSWilly Tu  * This function will return the corresponding Redfish health state
309eee0013eSWilly Tu  *
310eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
311eee0013eSWilly Tu  *
312eee0013eSWilly Tu  * @return The corresponding Redfish health state
313eee0013eSWilly Tu  */
314eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState)
315eee0013eSWilly Tu {
316eee0013eSWilly Tu     if ((swState ==
317eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Active") ||
318eee0013eSWilly Tu         (swState == "xyz.openbmc_project.Software.Activation.Activations."
319eee0013eSWilly Tu                     "Activating") ||
320eee0013eSWilly Tu         (swState ==
321eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Ready"))
322eee0013eSWilly Tu     {
323eee0013eSWilly Tu         return "OK";
324eee0013eSWilly Tu     }
32562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sw state {} to Warning", swState);
326eee0013eSWilly Tu     return "Warning";
327eee0013eSWilly Tu }
328eee0013eSWilly Tu 
329eee0013eSWilly Tu /**
330eee0013eSWilly Tu  * @brief Put status of input swId into json response
331eee0013eSWilly Tu  *
332eee0013eSWilly Tu  * This function will put the appropriate Redfish state of the input
333eee0013eSWilly Tu  * software id to ["Status"]["State"] within the json response
334eee0013eSWilly Tu  *
335ac106bf6SEd Tanous  * @param[i,o] asyncResp    Async response object
336eee0013eSWilly Tu  * @param[i]   swId     The software ID to get status for
337eee0013eSWilly Tu  * @param[i]   dbusSvc  The dbus service implementing the software object
338eee0013eSWilly Tu  *
339eee0013eSWilly Tu  * @return void
340eee0013eSWilly Tu  */
341eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
342eee0013eSWilly Tu                         const std::shared_ptr<std::string>& swId,
343eee0013eSWilly Tu                         const std::string& dbusSvc)
344eee0013eSWilly Tu {
34562598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSwStatus: swId {} svc {}", *swId, dbusSvc);
346eee0013eSWilly Tu 
347d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
348d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, dbusSvc,
349d1bde9e5SKrzysztof Grobelny         "/xyz/openbmc_project/software/" + *swId,
350d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Activation",
351eee0013eSWilly Tu         [asyncResp,
3528b24275dSEd Tanous          swId](const boost::system::error_code& ec,
353eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
3548b24275dSEd Tanous         if (ec)
355eee0013eSWilly Tu         {
356eee0013eSWilly Tu             // not all swtypes are updateable, this is ok
357eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
358eee0013eSWilly Tu             return;
359eee0013eSWilly Tu         }
360d1bde9e5SKrzysztof Grobelny 
361eee0013eSWilly Tu         const std::string* swInvActivation = nullptr;
362d1bde9e5SKrzysztof Grobelny 
363d1bde9e5SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
364d1bde9e5SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation",
365d1bde9e5SKrzysztof Grobelny             swInvActivation);
366d1bde9e5SKrzysztof Grobelny 
367d1bde9e5SKrzysztof Grobelny         if (!success)
368eee0013eSWilly Tu         {
369d1bde9e5SKrzysztof Grobelny             messages::internalError(asyncResp->res);
370d1bde9e5SKrzysztof Grobelny             return;
371eee0013eSWilly Tu         }
372eee0013eSWilly Tu 
373eee0013eSWilly Tu         if (swInvActivation == nullptr)
374eee0013eSWilly Tu         {
375eee0013eSWilly Tu             messages::internalError(asyncResp->res);
376eee0013eSWilly Tu             return;
377eee0013eSWilly Tu         }
378d1bde9e5SKrzysztof Grobelny 
37962598e31SEd Tanous         BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation);
380eee0013eSWilly Tu         asyncResp->res.jsonValue["Status"]["State"] =
381eee0013eSWilly Tu             getRedfishSwState(*swInvActivation);
382eee0013eSWilly Tu         asyncResp->res.jsonValue["Status"]["Health"] =
383eee0013eSWilly Tu             getRedfishSwHealth(*swInvActivation);
384d1bde9e5SKrzysztof Grobelny     });
385eee0013eSWilly Tu }
386eee0013eSWilly Tu 
387c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints(
388c018f705SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
389c018f705SJagpal Singh Gill     const std::shared_ptr<std::string>& swId,
390c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
391c018f705SJagpal Singh Gill     const dbus::utility::MapperEndPoints& objPaths)
392c018f705SJagpal Singh Gill {
393c018f705SJagpal Singh Gill     if (ec)
394c018f705SJagpal Singh Gill     {
395c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
396c018f705SJagpal Singh Gill         // System can exist with no updateable software,
397c018f705SJagpal Singh Gill         // so don't throw error here.
398c018f705SJagpal Singh Gill         return;
399c018f705SJagpal Singh Gill     }
400c018f705SJagpal Singh Gill     sdbusplus::message::object_path reqSwObjPath(
401c018f705SJagpal Singh Gill         "/xyz/openbmc_project/software");
402c018f705SJagpal Singh Gill     reqSwObjPath = reqSwObjPath / *swId;
403c018f705SJagpal Singh Gill 
404c018f705SJagpal Singh Gill     if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end())
405c018f705SJagpal Singh Gill     {
406c018f705SJagpal Singh Gill         asyncResp->res.jsonValue["Updateable"] = true;
407c018f705SJagpal Singh Gill         return;
408c018f705SJagpal Singh Gill     }
409c018f705SJagpal Singh Gill }
410c018f705SJagpal Singh Gill 
411c018f705SJagpal Singh Gill inline void
412c018f705SJagpal Singh Gill     handleUpdateableObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
413c018f705SJagpal Singh Gill                            const boost::system::error_code& ec,
414c018f705SJagpal Singh Gill                            const dbus::utility::MapperGetObject& objectInfo)
415c018f705SJagpal Singh Gill {
416c018f705SJagpal Singh Gill     if (ec)
417c018f705SJagpal Singh Gill     {
418c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
419c018f705SJagpal Singh Gill         // System can exist with no updateable software,
420c018f705SJagpal Singh Gill         // so don't throw error here.
421c018f705SJagpal Singh Gill         return;
422c018f705SJagpal Singh Gill     }
423c018f705SJagpal Singh Gill     if (objectInfo.empty())
424c018f705SJagpal Singh Gill     {
425c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG("No updateable software found");
426c018f705SJagpal Singh Gill         // System can exist with no updateable software,
427c018f705SJagpal Singh Gill         // so don't throw error here.
428c018f705SJagpal Singh Gill         return;
429c018f705SJagpal Singh Gill     }
430c018f705SJagpal Singh Gill     asyncResp->res.jsonValue["Updateable"] = true;
431c018f705SJagpal Singh Gill }
432c018f705SJagpal Singh Gill 
433eee0013eSWilly Tu /**
434eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
435eee0013eSWilly Tu  *
436eee0013eSWilly Tu  * This function checks whether software inventory component
437eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
438eee0013eSWilly Tu  * Property.
439eee0013eSWilly Tu  *
440eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
441eee0013eSWilly Tu  * @param[i]   swId       The software ID
442eee0013eSWilly Tu  */
443eee0013eSWilly Tu inline void
444eee0013eSWilly Tu     getSwUpdatableStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
445eee0013eSWilly Tu                          const std::shared_ptr<std::string>& swId)
446eee0013eSWilly Tu {
447c018f705SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
448c018f705SJagpal Singh Gill     {
449c018f705SJagpal Singh Gill         sdbusplus::message::object_path swObjectPath(
450c018f705SJagpal Singh Gill             "/xyz/openbmc_project/software");
451c018f705SJagpal Singh Gill         swObjectPath = swObjectPath / *swId;
452c018f705SJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
453c018f705SJagpal Singh Gill             "xyz.openbmc_project.Software.Update"};
454c018f705SJagpal Singh Gill         dbus::utility::getDbusObject(
455c018f705SJagpal Singh Gill             swObjectPath.str, interfaces,
456c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableObject, asyncResp));
457c018f705SJagpal Singh Gill     }
458c018f705SJagpal Singh Gill     else
459c018f705SJagpal Singh Gill     {
4606c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
461eee0013eSWilly Tu             "/xyz/openbmc_project/software/updateable",
462c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableEndpoints, asyncResp, swId));
463eee0013eSWilly Tu     }
464eee0013eSWilly Tu }
465eee0013eSWilly Tu 
466eee0013eSWilly Tu } // namespace sw_util
467eee0013eSWilly Tu } // namespace redfish
468