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