xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision a5f87d487143a5478528826bab72b9f5a093f305)
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 
70f8010a3dSEd Tanous inline void afterGetProperties(
71f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
72f8010a3dSEd Tanous     const std::string& swId, bool runningImage,
73f8010a3dSEd Tanous     const std::string& swVersionPurpose,
74f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
75f8010a3dSEd Tanous     const boost::system::error_code& ec,
76f8010a3dSEd Tanous     const dbus::utility::DBusPropertiesMap& propertiesList)
77f8010a3dSEd Tanous {
78f8010a3dSEd Tanous     if (ec)
79f8010a3dSEd Tanous     {
80f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error_code = {}", ec);
81f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
82f8010a3dSEd Tanous         // Have seen the code update app delete the
83f8010a3dSEd Tanous         // D-Bus object, during code update, between
84f8010a3dSEd Tanous         // the call to mapper and here. Just leave
85f8010a3dSEd Tanous         // these properties off if resource not
86f8010a3dSEd Tanous         // found.
87f8010a3dSEd Tanous         if (ec.value() == EBADR)
88f8010a3dSEd Tanous         {
89f8010a3dSEd Tanous             return;
90f8010a3dSEd Tanous         }
91f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
92f8010a3dSEd Tanous         return;
93f8010a3dSEd Tanous     }
94f8010a3dSEd Tanous     // example propertiesList
95f8010a3dSEd Tanous     // a{sv} 2 "Version" s
96f8010a3dSEd Tanous     // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
97f8010a3dSEd Tanous     // s
98f8010a3dSEd Tanous     // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
99f8010a3dSEd Tanous     const std::string* version = nullptr;
100f8010a3dSEd Tanous     const std::string* swInvPurpose = nullptr;
101f8010a3dSEd Tanous 
102f8010a3dSEd Tanous     const bool success = sdbusplus::unpackPropertiesNoThrow(
103f8010a3dSEd Tanous         dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
104f8010a3dSEd Tanous         swInvPurpose, "Version", version);
105f8010a3dSEd Tanous 
106f8010a3dSEd Tanous     if (!success)
107f8010a3dSEd Tanous     {
108f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
109f8010a3dSEd Tanous         return;
110f8010a3dSEd Tanous     }
111f8010a3dSEd Tanous 
112f8010a3dSEd Tanous     if (version == nullptr || version->empty())
113f8010a3dSEd Tanous     {
114f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
115f8010a3dSEd Tanous         return;
116f8010a3dSEd Tanous     }
117f8010a3dSEd Tanous     if (swInvPurpose == nullptr || *swInvPurpose != swVersionPurpose)
118f8010a3dSEd Tanous     {
119f8010a3dSEd Tanous         // Not purpose we're looking for
120f8010a3dSEd Tanous         return;
121f8010a3dSEd Tanous     }
122f8010a3dSEd Tanous 
123f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image ID: {}", swId);
124f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Running image: {}", runningImage);
125f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose);
126f8010a3dSEd Tanous 
127f8010a3dSEd Tanous     if (populateLinkToImages)
128f8010a3dSEd Tanous     {
129f8010a3dSEd Tanous         nlohmann::json& softwareImageMembers =
130f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["SoftwareImages"];
131f8010a3dSEd Tanous         // Firmware images are at
132f8010a3dSEd Tanous         // /redfish/v1/UpdateService/FirmwareInventory/<Id>
133f8010a3dSEd Tanous         // e.g. .../FirmwareInventory/82d3ec86
134f8010a3dSEd Tanous         nlohmann::json::object_t member;
135f8010a3dSEd Tanous         member["@odata.id"] = boost::urls::format(
136f8010a3dSEd Tanous             "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
137f8010a3dSEd Tanous         softwareImageMembers.emplace_back(std::move(member));
138f8010a3dSEd Tanous         asyncResp->res.jsonValue["Links"]["SoftwareImages@odata.count"] =
139f8010a3dSEd Tanous             softwareImageMembers.size();
140f8010a3dSEd Tanous 
141f8010a3dSEd Tanous         if (runningImage)
142f8010a3dSEd Tanous         {
143f8010a3dSEd Tanous             nlohmann::json::object_t runningMember;
144f8010a3dSEd Tanous             runningMember["@odata.id"] = boost::urls::format(
145f8010a3dSEd Tanous                 "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
146f8010a3dSEd Tanous             // Create the link to the running image
147f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["ActiveSoftwareImage"] =
148f8010a3dSEd Tanous                 std::move(runningMember);
149f8010a3dSEd Tanous         }
150f8010a3dSEd Tanous     }
151f8010a3dSEd Tanous     if (!activeVersionPropName.empty() && runningImage)
152f8010a3dSEd Tanous     {
153f8010a3dSEd Tanous         asyncResp->res.jsonValue[activeVersionPropName] = *version;
154f8010a3dSEd Tanous     }
155f8010a3dSEd Tanous }
156f8010a3dSEd Tanous 
157f8010a3dSEd Tanous inline void afterGetSubtree(
158f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
159f8010a3dSEd Tanous     const std::string& swVersionPurpose,
160f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
161f8010a3dSEd Tanous     const std::vector<std::string>& functionalSwIds,
162f8010a3dSEd Tanous     const boost::system::error_code& ec,
163f8010a3dSEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
164f8010a3dSEd Tanous {
165f8010a3dSEd Tanous     if (ec)
166f8010a3dSEd Tanous     {
167f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error_code = {}", ec);
168f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
169f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
170f8010a3dSEd Tanous         return;
171f8010a3dSEd Tanous     }
172f8010a3dSEd Tanous 
173f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
174f8010a3dSEd Tanous 
175f8010a3dSEd Tanous     for (const std::pair<
176f8010a3dSEd Tanous              std::string,
177f8010a3dSEd Tanous              std::vector<std::pair<std::string, std::vector<std::string>>>>&
178f8010a3dSEd Tanous              obj : subtree)
179f8010a3dSEd Tanous     {
180f8010a3dSEd Tanous         sdbusplus::message::object_path path(obj.first);
181f8010a3dSEd Tanous         std::string swId = path.filename();
182f8010a3dSEd Tanous         if (swId.empty())
183f8010a3dSEd Tanous         {
184f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
185f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("Invalid software ID");
186f8010a3dSEd Tanous 
187f8010a3dSEd Tanous             return;
188f8010a3dSEd Tanous         }
189f8010a3dSEd Tanous 
190f8010a3dSEd Tanous         bool runningImage = false;
191f8010a3dSEd Tanous         // Look at Ids from
192f8010a3dSEd Tanous         // /xyz/openbmc_project/software/functional
193f8010a3dSEd Tanous         // to determine if this is
194f8010a3dSEd Tanous         // a running image
195f8010a3dSEd Tanous         if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end())
196f8010a3dSEd Tanous         {
197f8010a3dSEd Tanous             runningImage = true;
198f8010a3dSEd Tanous         }
199f8010a3dSEd Tanous 
200f8010a3dSEd Tanous         // Now grab its version
201f8010a3dSEd Tanous         // info
202deae6a78SEd Tanous         dbus::utility::getAllProperties(
203f8010a3dSEd Tanous             *crow::connections::systemBus, obj.second[0].first, obj.first,
204f8010a3dSEd Tanous             "xyz.openbmc_project.Software.Version",
205f8010a3dSEd Tanous             [asyncResp, swId, runningImage, swVersionPurpose,
206f8010a3dSEd Tanous              activeVersionPropName, populateLinkToImages](
207f8010a3dSEd Tanous                 const boost::system::error_code& ec3,
208f8010a3dSEd Tanous                 const dbus::utility::DBusPropertiesMap& propertiesList) {
209f8010a3dSEd Tanous                 afterGetProperties(asyncResp, swId, runningImage,
210f8010a3dSEd Tanous                                    swVersionPurpose, activeVersionPropName,
211f8010a3dSEd Tanous                                    populateLinkToImages, ec3, propertiesList);
212f8010a3dSEd Tanous             });
213f8010a3dSEd Tanous     }
214f8010a3dSEd Tanous }
215f8010a3dSEd Tanous 
216f8010a3dSEd Tanous inline void afterAssociatedEndpoints(
217f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218f8010a3dSEd Tanous     const std::string& swVersionPurpose,
219f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
220f8010a3dSEd Tanous     const boost::system::error_code& ec,
221f8010a3dSEd Tanous     const dbus::utility::MapperEndPoints& functionalSw)
222f8010a3dSEd Tanous {
223f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
224f8010a3dSEd Tanous     if (ec)
225f8010a3dSEd Tanous     {
226*a5f87d48SGunnar Mills         BMCWEB_LOG_DEBUG("error_code = {}", ec);
227*a5f87d48SGunnar Mills         BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
228f8010a3dSEd Tanous         // No functional software for this swVersionPurpose, so just
229f8010a3dSEd Tanous         return;
230f8010a3dSEd Tanous     }
231f8010a3dSEd Tanous 
232f8010a3dSEd Tanous     if (functionalSw.empty())
233f8010a3dSEd Tanous     {
234f8010a3dSEd Tanous         // Could keep going and try to populate SoftwareImages
235f8010a3dSEd Tanous         // but something is seriously wrong, so just fail
236f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("Zero functional software in system");
237f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
238f8010a3dSEd Tanous         return;
239f8010a3dSEd Tanous     }
240f8010a3dSEd Tanous 
241f8010a3dSEd Tanous     std::vector<std::string> functionalSwIds;
242f8010a3dSEd Tanous     // example functionalSw:
243f8010a3dSEd Tanous     // v as 2 "/xyz/openbmc_project/software/ace821ef"
244f8010a3dSEd Tanous     //        "/xyz/openbmc_project/software/230fb078"
245f8010a3dSEd Tanous     for (const auto& sw : functionalSw)
246f8010a3dSEd Tanous     {
247f8010a3dSEd Tanous         sdbusplus::message::object_path path(sw);
248f8010a3dSEd Tanous         std::string leaf = path.filename();
249f8010a3dSEd Tanous         if (leaf.empty())
250f8010a3dSEd Tanous         {
251f8010a3dSEd Tanous             continue;
252f8010a3dSEd Tanous         }
253f8010a3dSEd Tanous 
254f8010a3dSEd Tanous         functionalSwIds.push_back(leaf);
255f8010a3dSEd Tanous     }
256f8010a3dSEd Tanous 
257f8010a3dSEd Tanous     constexpr std::array<std::string_view, 1> interfaces = {
258f8010a3dSEd Tanous         "xyz.openbmc_project.Software.Version"};
259f8010a3dSEd Tanous     dbus::utility::getSubTree(
260f8010a3dSEd Tanous         "/xyz/openbmc_project/software", 0, interfaces,
261f8010a3dSEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
262f8010a3dSEd Tanous          populateLinkToImages, functionalSwIds](
263f8010a3dSEd Tanous             const boost::system::error_code& ec2,
264f8010a3dSEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
265f8010a3dSEd Tanous             afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName,
266f8010a3dSEd Tanous                             populateLinkToImages, functionalSwIds, ec2,
267f8010a3dSEd Tanous                             subtree);
268f8010a3dSEd Tanous         });
269f8010a3dSEd Tanous }
270f8010a3dSEd 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) {
303f8010a3dSEd Tanous             afterAssociatedEndpoints(asyncResp, swVersionPurpose,
304f8010a3dSEd Tanous                                      activeVersionPropName,
305f8010a3dSEd 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 
380deae6a78SEd Tanous     dbus::utility::getAllProperties(
381deae6a78SEd Tanous         dbusSvc, "/xyz/openbmc_project/software/" + *swId,
382d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Activation",
383eee0013eSWilly Tu         [asyncResp,
3848b24275dSEd Tanous          swId](const boost::system::error_code& ec,
385eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
3868b24275dSEd Tanous             if (ec)
387eee0013eSWilly Tu             {
388eee0013eSWilly Tu                 // not all swtypes are updateable, this is ok
389539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
390539d8c6bSEd Tanous                     resource::State::Enabled;
391eee0013eSWilly Tu                 return;
392eee0013eSWilly Tu             }
393d1bde9e5SKrzysztof Grobelny 
394eee0013eSWilly Tu             const std::string* swInvActivation = nullptr;
395d1bde9e5SKrzysztof Grobelny 
396d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
397d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation",
398d1bde9e5SKrzysztof Grobelny                 swInvActivation);
399d1bde9e5SKrzysztof Grobelny 
400d1bde9e5SKrzysztof Grobelny             if (!success)
401eee0013eSWilly Tu             {
402d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
403d1bde9e5SKrzysztof Grobelny                 return;
404eee0013eSWilly Tu             }
405eee0013eSWilly Tu 
406eee0013eSWilly Tu             if (swInvActivation == nullptr)
407eee0013eSWilly Tu             {
408eee0013eSWilly Tu                 messages::internalError(asyncResp->res);
409eee0013eSWilly Tu                 return;
410eee0013eSWilly Tu             }
411d1bde9e5SKrzysztof Grobelny 
41262598e31SEd Tanous             BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation);
413eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] =
414eee0013eSWilly Tu                 getRedfishSwState(*swInvActivation);
415eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["Health"] =
416eee0013eSWilly Tu                 getRedfishSwHealth(*swInvActivation);
417d1bde9e5SKrzysztof Grobelny         });
418eee0013eSWilly Tu }
419eee0013eSWilly Tu 
420c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints(
421c018f705SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
422c018f705SJagpal Singh Gill     const std::shared_ptr<std::string>& swId,
423c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
424c018f705SJagpal Singh Gill     const dbus::utility::MapperEndPoints& objPaths)
425c018f705SJagpal Singh Gill {
426c018f705SJagpal Singh Gill     if (ec)
427c018f705SJagpal Singh Gill     {
428c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
429c018f705SJagpal Singh Gill         // System can exist with no updateable software,
430c018f705SJagpal Singh Gill         // so don't throw error here.
431c018f705SJagpal Singh Gill         return;
432c018f705SJagpal Singh Gill     }
433c018f705SJagpal Singh Gill     sdbusplus::message::object_path reqSwObjPath(
434c018f705SJagpal Singh Gill         "/xyz/openbmc_project/software");
435c018f705SJagpal Singh Gill     reqSwObjPath = reqSwObjPath / *swId;
436c018f705SJagpal Singh Gill 
437c018f705SJagpal Singh Gill     if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end())
438c018f705SJagpal Singh Gill     {
439c018f705SJagpal Singh Gill         asyncResp->res.jsonValue["Updateable"] = true;
440c018f705SJagpal Singh Gill         return;
441c018f705SJagpal Singh Gill     }
442c018f705SJagpal Singh Gill }
443c018f705SJagpal Singh Gill 
444c018f705SJagpal Singh Gill inline void
445c018f705SJagpal Singh Gill     handleUpdateableObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
446c018f705SJagpal Singh Gill                            const boost::system::error_code& ec,
447c018f705SJagpal Singh Gill                            const dbus::utility::MapperGetObject& objectInfo)
448c018f705SJagpal Singh Gill {
449c018f705SJagpal Singh Gill     if (ec)
450c018f705SJagpal Singh Gill     {
451c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
452c018f705SJagpal Singh Gill         // System can exist with no updateable software,
453c018f705SJagpal Singh Gill         // so don't throw error here.
454c018f705SJagpal Singh Gill         return;
455c018f705SJagpal Singh Gill     }
456c018f705SJagpal Singh Gill     if (objectInfo.empty())
457c018f705SJagpal Singh Gill     {
458c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG("No updateable software found");
459c018f705SJagpal Singh Gill         // System can exist with no updateable software,
460c018f705SJagpal Singh Gill         // so don't throw error here.
461c018f705SJagpal Singh Gill         return;
462c018f705SJagpal Singh Gill     }
463c018f705SJagpal Singh Gill     asyncResp->res.jsonValue["Updateable"] = true;
464c018f705SJagpal Singh Gill }
465c018f705SJagpal Singh Gill 
466eee0013eSWilly Tu /**
467eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
468eee0013eSWilly Tu  *
469eee0013eSWilly Tu  * This function checks whether software inventory component
470eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
471eee0013eSWilly Tu  * Property.
472eee0013eSWilly Tu  *
473eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
474eee0013eSWilly Tu  * @param[i]   swId       The software ID
475eee0013eSWilly Tu  */
476eee0013eSWilly Tu inline void
477eee0013eSWilly Tu     getSwUpdatableStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
478eee0013eSWilly Tu                          const std::shared_ptr<std::string>& swId)
479eee0013eSWilly Tu {
480c018f705SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
481c018f705SJagpal Singh Gill     {
482c018f705SJagpal Singh Gill         sdbusplus::message::object_path swObjectPath(
483c018f705SJagpal Singh Gill             "/xyz/openbmc_project/software");
484c018f705SJagpal Singh Gill         swObjectPath = swObjectPath / *swId;
485c018f705SJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
486c018f705SJagpal Singh Gill             "xyz.openbmc_project.Software.Update"};
487c018f705SJagpal Singh Gill         dbus::utility::getDbusObject(
488c018f705SJagpal Singh Gill             swObjectPath.str, interfaces,
489c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableObject, asyncResp));
490c018f705SJagpal Singh Gill     }
491c018f705SJagpal Singh Gill     else
492c018f705SJagpal Singh Gill     {
4936c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
494eee0013eSWilly Tu             "/xyz/openbmc_project/software/updateable",
495c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableEndpoints, asyncResp, swId));
496eee0013eSWilly Tu     }
497eee0013eSWilly Tu }
498eee0013eSWilly Tu 
499eee0013eSWilly Tu } // namespace sw_util
500eee0013eSWilly Tu } // namespace redfish
501