xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision f8010a3df0dfb00918217f092b3f5b31c7ce412c)
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>
167f23576aSJagpal 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 
347f23576aSJagpal Singh Gill inline std::optional<sdbusplus::message::object_path>
357f23576aSJagpal Singh Gill     getFunctionalSoftwarePath(const std::string& swType)
367f23576aSJagpal Singh Gill {
377f23576aSJagpal Singh Gill     if (swType == bmcPurpose)
387f23576aSJagpal Singh Gill     {
397f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
407f23576aSJagpal Singh Gill         {
417f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
427f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bmc/functional");
437f23576aSJagpal Singh Gill         }
447f23576aSJagpal Singh Gill         else
457f23576aSJagpal Singh Gill         {
467f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
477f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
487f23576aSJagpal Singh Gill         }
497f23576aSJagpal Singh Gill     }
507f23576aSJagpal Singh Gill     else if (swType == biosPurpose)
517f23576aSJagpal Singh Gill     {
527f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
537f23576aSJagpal Singh Gill         {
547f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
557f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bios/functional");
567f23576aSJagpal Singh Gill         }
577f23576aSJagpal Singh Gill         else
587f23576aSJagpal Singh Gill         {
597f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
607f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
617f23576aSJagpal Singh Gill         }
627f23576aSJagpal Singh Gill     }
637f23576aSJagpal Singh Gill     else
647f23576aSJagpal Singh Gill     {
657f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("No valid software path");
667f23576aSJagpal Singh Gill         return std::nullopt;
677f23576aSJagpal Singh Gill     }
687f23576aSJagpal Singh Gill }
697f23576aSJagpal Singh Gill 
70*f8010a3dSEd Tanous inline void afterGetProperties(
71*f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
72*f8010a3dSEd Tanous     const std::string& swId, bool runningImage,
73*f8010a3dSEd Tanous     const std::string& swVersionPurpose,
74*f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
75*f8010a3dSEd Tanous     const boost::system::error_code& ec,
76*f8010a3dSEd Tanous     const dbus::utility::DBusPropertiesMap& propertiesList)
77*f8010a3dSEd Tanous {
78*f8010a3dSEd Tanous     if (ec)
79*f8010a3dSEd Tanous     {
80*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error_code = {}", ec);
81*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
82*f8010a3dSEd Tanous         // Have seen the code update app delete the
83*f8010a3dSEd Tanous         // D-Bus object, during code update, between
84*f8010a3dSEd Tanous         // the call to mapper and here. Just leave
85*f8010a3dSEd Tanous         // these properties off if resource not
86*f8010a3dSEd Tanous         // found.
87*f8010a3dSEd Tanous         if (ec.value() == EBADR)
88*f8010a3dSEd Tanous         {
89*f8010a3dSEd Tanous             return;
90*f8010a3dSEd Tanous         }
91*f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
92*f8010a3dSEd Tanous         return;
93*f8010a3dSEd Tanous     }
94*f8010a3dSEd Tanous     // example propertiesList
95*f8010a3dSEd Tanous     // a{sv} 2 "Version" s
96*f8010a3dSEd Tanous     // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
97*f8010a3dSEd Tanous     // s
98*f8010a3dSEd Tanous     // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
99*f8010a3dSEd Tanous     const std::string* version = nullptr;
100*f8010a3dSEd Tanous     const std::string* swInvPurpose = nullptr;
101*f8010a3dSEd Tanous 
102*f8010a3dSEd Tanous     const bool success = sdbusplus::unpackPropertiesNoThrow(
103*f8010a3dSEd Tanous         dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
104*f8010a3dSEd Tanous         swInvPurpose, "Version", version);
105*f8010a3dSEd Tanous 
106*f8010a3dSEd Tanous     if (!success)
107*f8010a3dSEd Tanous     {
108*f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
109*f8010a3dSEd Tanous         return;
110*f8010a3dSEd Tanous     }
111*f8010a3dSEd Tanous 
112*f8010a3dSEd Tanous     if (version == nullptr || version->empty())
113*f8010a3dSEd Tanous     {
114*f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
115*f8010a3dSEd Tanous         return;
116*f8010a3dSEd Tanous     }
117*f8010a3dSEd Tanous     if (swInvPurpose == nullptr || *swInvPurpose != swVersionPurpose)
118*f8010a3dSEd Tanous     {
119*f8010a3dSEd Tanous         // Not purpose we're looking for
120*f8010a3dSEd Tanous         return;
121*f8010a3dSEd Tanous     }
122*f8010a3dSEd Tanous 
123*f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image ID: {}", swId);
124*f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Running image: {}", runningImage);
125*f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose);
126*f8010a3dSEd Tanous 
127*f8010a3dSEd Tanous     if (populateLinkToImages)
128*f8010a3dSEd Tanous     {
129*f8010a3dSEd Tanous         nlohmann::json& softwareImageMembers =
130*f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["SoftwareImages"];
131*f8010a3dSEd Tanous         // Firmware images are at
132*f8010a3dSEd Tanous         // /redfish/v1/UpdateService/FirmwareInventory/<Id>
133*f8010a3dSEd Tanous         // e.g. .../FirmwareInventory/82d3ec86
134*f8010a3dSEd Tanous         nlohmann::json::object_t member;
135*f8010a3dSEd Tanous         member["@odata.id"] = boost::urls::format(
136*f8010a3dSEd Tanous             "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
137*f8010a3dSEd Tanous         softwareImageMembers.emplace_back(std::move(member));
138*f8010a3dSEd Tanous         asyncResp->res.jsonValue["Links"]["SoftwareImages@odata.count"] =
139*f8010a3dSEd Tanous             softwareImageMembers.size();
140*f8010a3dSEd Tanous 
141*f8010a3dSEd Tanous         if (runningImage)
142*f8010a3dSEd Tanous         {
143*f8010a3dSEd Tanous             nlohmann::json::object_t runningMember;
144*f8010a3dSEd Tanous             runningMember["@odata.id"] = boost::urls::format(
145*f8010a3dSEd Tanous                 "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
146*f8010a3dSEd Tanous             // Create the link to the running image
147*f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["ActiveSoftwareImage"] =
148*f8010a3dSEd Tanous                 std::move(runningMember);
149*f8010a3dSEd Tanous         }
150*f8010a3dSEd Tanous     }
151*f8010a3dSEd Tanous     if (!activeVersionPropName.empty() && runningImage)
152*f8010a3dSEd Tanous     {
153*f8010a3dSEd Tanous         asyncResp->res.jsonValue[activeVersionPropName] = *version;
154*f8010a3dSEd Tanous     }
155*f8010a3dSEd Tanous }
156*f8010a3dSEd Tanous 
157*f8010a3dSEd Tanous inline void afterGetSubtree(
158*f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
159*f8010a3dSEd Tanous     const std::string& swVersionPurpose,
160*f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
161*f8010a3dSEd Tanous     const std::vector<std::string>& functionalSwIds,
162*f8010a3dSEd Tanous     const boost::system::error_code& ec,
163*f8010a3dSEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
164*f8010a3dSEd Tanous {
165*f8010a3dSEd Tanous     if (ec)
166*f8010a3dSEd Tanous     {
167*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error_code = {}", ec);
168*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
169*f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
170*f8010a3dSEd Tanous         return;
171*f8010a3dSEd Tanous     }
172*f8010a3dSEd Tanous 
173*f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
174*f8010a3dSEd Tanous 
175*f8010a3dSEd Tanous     for (const std::pair<
176*f8010a3dSEd Tanous              std::string,
177*f8010a3dSEd Tanous              std::vector<std::pair<std::string, std::vector<std::string>>>>&
178*f8010a3dSEd Tanous              obj : subtree)
179*f8010a3dSEd Tanous     {
180*f8010a3dSEd Tanous         sdbusplus::message::object_path path(obj.first);
181*f8010a3dSEd Tanous         std::string swId = path.filename();
182*f8010a3dSEd Tanous         if (swId.empty())
183*f8010a3dSEd Tanous         {
184*f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
185*f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("Invalid software ID");
186*f8010a3dSEd Tanous 
187*f8010a3dSEd Tanous             return;
188*f8010a3dSEd Tanous         }
189*f8010a3dSEd Tanous 
190*f8010a3dSEd Tanous         bool runningImage = false;
191*f8010a3dSEd Tanous         // Look at Ids from
192*f8010a3dSEd Tanous         // /xyz/openbmc_project/software/functional
193*f8010a3dSEd Tanous         // to determine if this is
194*f8010a3dSEd Tanous         // a running image
195*f8010a3dSEd Tanous         if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end())
196*f8010a3dSEd Tanous         {
197*f8010a3dSEd Tanous             runningImage = true;
198*f8010a3dSEd Tanous         }
199*f8010a3dSEd Tanous 
200*f8010a3dSEd Tanous         // Now grab its version
201*f8010a3dSEd Tanous         // info
202*f8010a3dSEd Tanous         sdbusplus::asio::getAllProperties(
203*f8010a3dSEd Tanous             *crow::connections::systemBus, obj.second[0].first, obj.first,
204*f8010a3dSEd Tanous             "xyz.openbmc_project.Software.Version",
205*f8010a3dSEd Tanous             [asyncResp, swId, runningImage, swVersionPurpose,
206*f8010a3dSEd Tanous              activeVersionPropName, populateLinkToImages](
207*f8010a3dSEd Tanous                 const boost::system::error_code& ec3,
208*f8010a3dSEd Tanous                 const dbus::utility::DBusPropertiesMap& propertiesList) {
209*f8010a3dSEd Tanous                 afterGetProperties(asyncResp, swId, runningImage,
210*f8010a3dSEd Tanous                                    swVersionPurpose, activeVersionPropName,
211*f8010a3dSEd Tanous                                    populateLinkToImages, ec3, propertiesList);
212*f8010a3dSEd Tanous             });
213*f8010a3dSEd Tanous     }
214*f8010a3dSEd Tanous }
215*f8010a3dSEd Tanous 
216*f8010a3dSEd Tanous inline void afterAssociatedEndpoints(
217*f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218*f8010a3dSEd Tanous     const std::string& swVersionPurpose,
219*f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
220*f8010a3dSEd Tanous     const boost::system::error_code& ec,
221*f8010a3dSEd Tanous     const dbus::utility::MapperEndPoints& functionalSw)
222*f8010a3dSEd Tanous {
223*f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
224*f8010a3dSEd Tanous     if (ec)
225*f8010a3dSEd Tanous     {
226*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error_code = {}", ec);
227*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
228*f8010a3dSEd Tanous         // No functional software for this swVersionPurpose, so just
229*f8010a3dSEd Tanous         return;
230*f8010a3dSEd Tanous     }
231*f8010a3dSEd Tanous 
232*f8010a3dSEd Tanous     if (functionalSw.empty())
233*f8010a3dSEd Tanous     {
234*f8010a3dSEd Tanous         // Could keep going and try to populate SoftwareImages
235*f8010a3dSEd Tanous         // but something is seriously wrong, so just fail
236*f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("Zero functional software in system");
237*f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
238*f8010a3dSEd Tanous         return;
239*f8010a3dSEd Tanous     }
240*f8010a3dSEd Tanous 
241*f8010a3dSEd Tanous     std::vector<std::string> functionalSwIds;
242*f8010a3dSEd Tanous     // example functionalSw:
243*f8010a3dSEd Tanous     // v as 2 "/xyz/openbmc_project/software/ace821ef"
244*f8010a3dSEd Tanous     //        "/xyz/openbmc_project/software/230fb078"
245*f8010a3dSEd Tanous     for (const auto& sw : functionalSw)
246*f8010a3dSEd Tanous     {
247*f8010a3dSEd Tanous         sdbusplus::message::object_path path(sw);
248*f8010a3dSEd Tanous         std::string leaf = path.filename();
249*f8010a3dSEd Tanous         if (leaf.empty())
250*f8010a3dSEd Tanous         {
251*f8010a3dSEd Tanous             continue;
252*f8010a3dSEd Tanous         }
253*f8010a3dSEd Tanous 
254*f8010a3dSEd Tanous         functionalSwIds.push_back(leaf);
255*f8010a3dSEd Tanous     }
256*f8010a3dSEd Tanous 
257*f8010a3dSEd Tanous     constexpr std::array<std::string_view, 1> interfaces = {
258*f8010a3dSEd Tanous         "xyz.openbmc_project.Software.Version"};
259*f8010a3dSEd Tanous     dbus::utility::getSubTree(
260*f8010a3dSEd Tanous         "/xyz/openbmc_project/software", 0, interfaces,
261*f8010a3dSEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
262*f8010a3dSEd Tanous          populateLinkToImages, functionalSwIds](
263*f8010a3dSEd Tanous             const boost::system::error_code& ec2,
264*f8010a3dSEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
265*f8010a3dSEd Tanous             afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName,
266*f8010a3dSEd Tanous                             populateLinkToImages, functionalSwIds, ec2,
267*f8010a3dSEd Tanous                             subtree);
268*f8010a3dSEd Tanous         });
269*f8010a3dSEd Tanous }
270*f8010a3dSEd Tanous 
271eee0013eSWilly Tu /**
272eee0013eSWilly Tu  * @brief Populate the running software version and image links
273eee0013eSWilly Tu  *
274ac106bf6SEd Tanous  * @param[i,o] asyncResp             Async response object
275eee0013eSWilly Tu  * @param[i]   swVersionPurpose  Indicates what target to look for
276ac106bf6SEd Tanous  * @param[i]   activeVersionPropName  Index in asyncResp->res.jsonValue to write
277eee0013eSWilly Tu  * the running software version to
278ac106bf6SEd Tanous  * @param[i]   populateLinkToImages  Populate asyncResp->res "Links"
279eee0013eSWilly Tu  * "ActiveSoftwareImage" with a link to the running software image and
280eee0013eSWilly Tu  * "SoftwareImages" with a link to the all its software images
281eee0013eSWilly Tu  *
282eee0013eSWilly Tu  * @return void
283eee0013eSWilly Tu  */
284ac106bf6SEd Tanous inline void populateSoftwareInformation(
285ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
286eee0013eSWilly Tu     const std::string& swVersionPurpose,
287ac106bf6SEd Tanous     const std::string& activeVersionPropName, const bool populateLinkToImages)
288eee0013eSWilly Tu {
2897f23576aSJagpal Singh Gill     auto swPath = getFunctionalSoftwarePath(swVersionPurpose);
2907f23576aSJagpal Singh Gill     if (!swPath)
2917f23576aSJagpal Singh Gill     {
2927f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("Invalid software type");
2937f23576aSJagpal Singh Gill         messages::internalError(asyncResp->res);
2947f23576aSJagpal Singh Gill         return;
2957f23576aSJagpal Singh Gill     }
296eee0013eSWilly Tu     // Used later to determine running (known on Redfish as active) Sw images
297a4eb761aSGeorge Liu     dbus::utility::getAssociationEndPoints(
2987f23576aSJagpal Singh Gill         swPath.value().str,
299ac106bf6SEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
300ac106bf6SEd Tanous          populateLinkToImages](
301a4eb761aSGeorge Liu             const boost::system::error_code& ec,
302a4eb761aSGeorge Liu             const dbus::utility::MapperEndPoints& functionalSw) {
303*f8010a3dSEd Tanous             afterAssociatedEndpoints(asyncResp, swVersionPurpose,
304*f8010a3dSEd Tanous                                      activeVersionPropName,
305*f8010a3dSEd Tanous                                      populateLinkToImages, ec, functionalSw);
306eee0013eSWilly Tu         });
307eee0013eSWilly Tu }
308eee0013eSWilly Tu 
309eee0013eSWilly Tu /**
310eee0013eSWilly Tu  * @brief Translate input swState to Redfish state
311eee0013eSWilly Tu  *
312eee0013eSWilly Tu  * This function will return the corresponding Redfish state
313eee0013eSWilly Tu  *
314eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
315eee0013eSWilly Tu  *
316eee0013eSWilly Tu  * @return The corresponding Redfish state
317eee0013eSWilly Tu  */
3180ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState)
319eee0013eSWilly Tu {
320eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active")
321eee0013eSWilly Tu     {
3220ec8b83dSEd Tanous         return resource::State::Enabled;
323eee0013eSWilly Tu     }
324eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
325eee0013eSWilly Tu                    "Activations.Activating")
326eee0013eSWilly Tu     {
3270ec8b83dSEd Tanous         return resource::State::Updating;
328eee0013eSWilly Tu     }
329eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
330eee0013eSWilly Tu                    "Activations.StandbySpare")
331eee0013eSWilly Tu     {
3320ec8b83dSEd Tanous         return resource::State::StandbySpare;
333eee0013eSWilly Tu     }
33462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Default sw state {} to Disabled", swState);
3350ec8b83dSEd Tanous     return resource::State::Disabled;
336eee0013eSWilly Tu }
337eee0013eSWilly Tu 
338eee0013eSWilly Tu /**
339eee0013eSWilly Tu  * @brief Translate input swState to Redfish health state
340eee0013eSWilly Tu  *
341eee0013eSWilly Tu  * This function will return the corresponding Redfish health state
342eee0013eSWilly Tu  *
343eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
344eee0013eSWilly Tu  *
345eee0013eSWilly Tu  * @return The corresponding Redfish health state
346eee0013eSWilly Tu  */
347eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState)
348eee0013eSWilly Tu {
349eee0013eSWilly Tu     if ((swState ==
350eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Active") ||
351eee0013eSWilly Tu         (swState == "xyz.openbmc_project.Software.Activation.Activations."
352eee0013eSWilly Tu                     "Activating") ||
353eee0013eSWilly Tu         (swState ==
354eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Ready"))
355eee0013eSWilly Tu     {
356eee0013eSWilly Tu         return "OK";
357eee0013eSWilly Tu     }
35862598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sw state {} to Warning", swState);
359eee0013eSWilly Tu     return "Warning";
360eee0013eSWilly Tu }
361eee0013eSWilly Tu 
362eee0013eSWilly Tu /**
363eee0013eSWilly Tu  * @brief Put status of input swId into json response
364eee0013eSWilly Tu  *
365eee0013eSWilly Tu  * This function will put the appropriate Redfish state of the input
366eee0013eSWilly Tu  * software id to ["Status"]["State"] within the json response
367eee0013eSWilly Tu  *
368ac106bf6SEd Tanous  * @param[i,o] asyncResp    Async response object
369eee0013eSWilly Tu  * @param[i]   swId     The software ID to get status for
370eee0013eSWilly Tu  * @param[i]   dbusSvc  The dbus service implementing the software object
371eee0013eSWilly Tu  *
372eee0013eSWilly Tu  * @return void
373eee0013eSWilly Tu  */
374eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
375eee0013eSWilly Tu                         const std::shared_ptr<std::string>& swId,
376eee0013eSWilly Tu                         const std::string& dbusSvc)
377eee0013eSWilly Tu {
37862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSwStatus: swId {} svc {}", *swId, dbusSvc);
379eee0013eSWilly Tu 
380d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
381d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, dbusSvc,
382d1bde9e5SKrzysztof Grobelny         "/xyz/openbmc_project/software/" + *swId,
383d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Activation",
384eee0013eSWilly Tu         [asyncResp,
3858b24275dSEd Tanous          swId](const boost::system::error_code& ec,
386eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
3878b24275dSEd Tanous             if (ec)
388eee0013eSWilly Tu             {
389eee0013eSWilly Tu                 // not all swtypes are updateable, this is ok
390539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
391539d8c6bSEd Tanous                     resource::State::Enabled;
392eee0013eSWilly Tu                 return;
393eee0013eSWilly Tu             }
394d1bde9e5SKrzysztof Grobelny 
395eee0013eSWilly Tu             const std::string* swInvActivation = nullptr;
396d1bde9e5SKrzysztof Grobelny 
397d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
398d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation",
399d1bde9e5SKrzysztof Grobelny                 swInvActivation);
400d1bde9e5SKrzysztof Grobelny 
401d1bde9e5SKrzysztof Grobelny             if (!success)
402eee0013eSWilly Tu             {
403d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
404d1bde9e5SKrzysztof Grobelny                 return;
405eee0013eSWilly Tu             }
406eee0013eSWilly Tu 
407eee0013eSWilly Tu             if (swInvActivation == nullptr)
408eee0013eSWilly Tu             {
409eee0013eSWilly Tu                 messages::internalError(asyncResp->res);
410eee0013eSWilly Tu                 return;
411eee0013eSWilly Tu             }
412d1bde9e5SKrzysztof Grobelny 
41362598e31SEd Tanous             BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation);
414eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] =
415eee0013eSWilly Tu                 getRedfishSwState(*swInvActivation);
416eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["Health"] =
417eee0013eSWilly Tu                 getRedfishSwHealth(*swInvActivation);
418d1bde9e5SKrzysztof Grobelny         });
419eee0013eSWilly Tu }
420eee0013eSWilly Tu 
421c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints(
422c018f705SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
423c018f705SJagpal Singh Gill     const std::shared_ptr<std::string>& swId,
424c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
425c018f705SJagpal Singh Gill     const dbus::utility::MapperEndPoints& objPaths)
426c018f705SJagpal Singh Gill {
427c018f705SJagpal Singh Gill     if (ec)
428c018f705SJagpal Singh Gill     {
429c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
430c018f705SJagpal Singh Gill         // System can exist with no updateable software,
431c018f705SJagpal Singh Gill         // so don't throw error here.
432c018f705SJagpal Singh Gill         return;
433c018f705SJagpal Singh Gill     }
434c018f705SJagpal Singh Gill     sdbusplus::message::object_path reqSwObjPath(
435c018f705SJagpal Singh Gill         "/xyz/openbmc_project/software");
436c018f705SJagpal Singh Gill     reqSwObjPath = reqSwObjPath / *swId;
437c018f705SJagpal Singh Gill 
438c018f705SJagpal Singh Gill     if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end())
439c018f705SJagpal Singh Gill     {
440c018f705SJagpal Singh Gill         asyncResp->res.jsonValue["Updateable"] = true;
441c018f705SJagpal Singh Gill         return;
442c018f705SJagpal Singh Gill     }
443c018f705SJagpal Singh Gill }
444c018f705SJagpal Singh Gill 
445c018f705SJagpal Singh Gill inline void
446c018f705SJagpal Singh Gill     handleUpdateableObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
447c018f705SJagpal Singh Gill                            const boost::system::error_code& ec,
448c018f705SJagpal Singh Gill                            const dbus::utility::MapperGetObject& objectInfo)
449c018f705SJagpal Singh Gill {
450c018f705SJagpal Singh Gill     if (ec)
451c018f705SJagpal Singh Gill     {
452c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
453c018f705SJagpal Singh Gill         // System can exist with no updateable software,
454c018f705SJagpal Singh Gill         // so don't throw error here.
455c018f705SJagpal Singh Gill         return;
456c018f705SJagpal Singh Gill     }
457c018f705SJagpal Singh Gill     if (objectInfo.empty())
458c018f705SJagpal Singh Gill     {
459c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG("No updateable software found");
460c018f705SJagpal Singh Gill         // System can exist with no updateable software,
461c018f705SJagpal Singh Gill         // so don't throw error here.
462c018f705SJagpal Singh Gill         return;
463c018f705SJagpal Singh Gill     }
464c018f705SJagpal Singh Gill     asyncResp->res.jsonValue["Updateable"] = true;
465c018f705SJagpal Singh Gill }
466c018f705SJagpal Singh Gill 
467eee0013eSWilly Tu /**
468eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
469eee0013eSWilly Tu  *
470eee0013eSWilly Tu  * This function checks whether software inventory component
471eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
472eee0013eSWilly Tu  * Property.
473eee0013eSWilly Tu  *
474eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
475eee0013eSWilly Tu  * @param[i]   swId       The software ID
476eee0013eSWilly Tu  */
477eee0013eSWilly Tu inline void
478eee0013eSWilly Tu     getSwUpdatableStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
479eee0013eSWilly Tu                          const std::shared_ptr<std::string>& swId)
480eee0013eSWilly Tu {
481c018f705SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
482c018f705SJagpal Singh Gill     {
483c018f705SJagpal Singh Gill         sdbusplus::message::object_path swObjectPath(
484c018f705SJagpal Singh Gill             "/xyz/openbmc_project/software");
485c018f705SJagpal Singh Gill         swObjectPath = swObjectPath / *swId;
486c018f705SJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
487c018f705SJagpal Singh Gill             "xyz.openbmc_project.Software.Update"};
488c018f705SJagpal Singh Gill         dbus::utility::getDbusObject(
489c018f705SJagpal Singh Gill             swObjectPath.str, interfaces,
490c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableObject, asyncResp));
491c018f705SJagpal Singh Gill     }
492c018f705SJagpal Singh Gill     else
493c018f705SJagpal Singh Gill     {
4946c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
495eee0013eSWilly Tu             "/xyz/openbmc_project/software/updateable",
496c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableEndpoints, asyncResp, swId));
497eee0013eSWilly Tu     }
498eee0013eSWilly Tu }
499eee0013eSWilly Tu 
500eee0013eSWilly Tu } // namespace sw_util
501eee0013eSWilly Tu } // namespace redfish
502