xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision fa712405fb3be628924ca06362e3ab3826b45495)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3eee0013eSWilly Tu #pragma once
4d7857201SEd Tanous #include "bmcweb_config.h"
5d7857201SEd Tanous 
63ccb3adbSEd Tanous #include "async_resp.hpp"
7177612aaSEd Tanous #include "boost_formatters.hpp"
8d7857201SEd Tanous #include "dbus_singleton.hpp"
93ccb3adbSEd Tanous #include "dbus_utility.hpp"
103ccb3adbSEd Tanous #include "error_messages.hpp"
113ccb3adbSEd Tanous #include "generated/enums/resource.hpp"
12d7857201SEd Tanous #include "logging.hpp"
133ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
143ccb3adbSEd Tanous 
15d7857201SEd Tanous #include <asm-generic/errno.h>
16d7857201SEd Tanous 
17e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
18ef4c65b7SEd Tanous #include <boost/url/format.hpp>
19d7857201SEd Tanous #include <nlohmann/json.hpp>
20d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
21d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
22eee0013eSWilly Tu 
23eee0013eSWilly Tu #include <algorithm>
24e99073f5SGeorge Liu #include <array>
25d7857201SEd Tanous #include <functional>
26d7857201SEd Tanous #include <memory>
277f23576aSJagpal Singh Gill #include <optional>
283544d2a7SEd Tanous #include <ranges>
29eee0013eSWilly Tu #include <string>
30e99073f5SGeorge Liu #include <string_view>
31d7857201SEd Tanous #include <utility>
32eee0013eSWilly Tu #include <vector>
33eee0013eSWilly Tu 
34eee0013eSWilly Tu namespace redfish
35eee0013eSWilly Tu {
36eee0013eSWilly Tu namespace sw_util
37eee0013eSWilly Tu {
38eee0013eSWilly Tu /* @brief String that indicates a bios software instance */
39eee0013eSWilly Tu constexpr const char* biosPurpose =
40eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
41eee0013eSWilly Tu 
42eee0013eSWilly Tu /* @brief String that indicates a BMC software instance */
43eee0013eSWilly Tu constexpr const char* bmcPurpose =
44eee0013eSWilly Tu     "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
45eee0013eSWilly Tu 
46504af5a0SPatrick Williams inline std::optional<sdbusplus::message::object_path> getFunctionalSoftwarePath(
47504af5a0SPatrick Williams     const std::string& swType)
487f23576aSJagpal Singh Gill {
497f23576aSJagpal Singh Gill     if (swType == bmcPurpose)
507f23576aSJagpal Singh Gill     {
517f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
527f23576aSJagpal Singh Gill         {
537f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
547f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bmc/functional");
557f23576aSJagpal Singh Gill         }
567f23576aSJagpal Singh Gill         else
577f23576aSJagpal Singh Gill         {
587f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
597f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
607f23576aSJagpal Singh Gill         }
617f23576aSJagpal Singh Gill     }
627f23576aSJagpal Singh Gill     else if (swType == biosPurpose)
637f23576aSJagpal Singh Gill     {
647f23576aSJagpal Singh Gill         if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
657f23576aSJagpal Singh Gill         {
667f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
677f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/bios/functional");
687f23576aSJagpal Singh Gill         }
697f23576aSJagpal Singh Gill         else
707f23576aSJagpal Singh Gill         {
717f23576aSJagpal Singh Gill             return sdbusplus::message::object_path(
727f23576aSJagpal Singh Gill                 "/xyz/openbmc_project/software/functional");
737f23576aSJagpal Singh Gill         }
747f23576aSJagpal Singh Gill     }
757f23576aSJagpal Singh Gill     else
767f23576aSJagpal Singh Gill     {
777f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("No valid software path");
787f23576aSJagpal Singh Gill         return std::nullopt;
797f23576aSJagpal Singh Gill     }
807f23576aSJagpal Singh Gill }
817f23576aSJagpal Singh Gill 
82f8010a3dSEd Tanous inline void afterGetProperties(
83f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
84f8010a3dSEd Tanous     const std::string& swId, bool runningImage,
85f8010a3dSEd Tanous     const std::string& swVersionPurpose,
86f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
87f8010a3dSEd Tanous     const boost::system::error_code& ec,
88f8010a3dSEd Tanous     const dbus::utility::DBusPropertiesMap& propertiesList)
89f8010a3dSEd Tanous {
90f8010a3dSEd Tanous     if (ec)
91f8010a3dSEd Tanous     {
92f8010a3dSEd Tanous         // Have seen the code update app delete the
93f8010a3dSEd Tanous         // D-Bus object, during code update, between
94f8010a3dSEd Tanous         // the call to mapper and here. Just leave
95f8010a3dSEd Tanous         // these properties off if resource not
96f8010a3dSEd Tanous         // found.
97fd4f088fSMyung Bae         if (ec.value() != EBADR)
98f8010a3dSEd Tanous         {
99fd4f088fSMyung Bae             BMCWEB_LOG_ERROR("error_code = {}", ec);
100f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
101fd4f088fSMyung Bae         }
102f8010a3dSEd Tanous         return;
103f8010a3dSEd Tanous     }
104f8010a3dSEd Tanous     // example propertiesList
105f8010a3dSEd Tanous     // a{sv} 2 "Version" s
106f8010a3dSEd Tanous     // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
107f8010a3dSEd Tanous     // s
108f8010a3dSEd Tanous     // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
109f8010a3dSEd Tanous     const std::string* version = nullptr;
110f8010a3dSEd Tanous     const std::string* swInvPurpose = nullptr;
111f8010a3dSEd Tanous 
112f8010a3dSEd Tanous     const bool success = sdbusplus::unpackPropertiesNoThrow(
113f8010a3dSEd Tanous         dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
114f8010a3dSEd Tanous         swInvPurpose, "Version", version);
115f8010a3dSEd Tanous 
116f8010a3dSEd Tanous     if (!success)
117f8010a3dSEd Tanous     {
118f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
119f8010a3dSEd Tanous         return;
120f8010a3dSEd Tanous     }
121f8010a3dSEd Tanous 
122*fa712405SDaniel Hsu     if (version == nullptr)
123f8010a3dSEd Tanous     {
124f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
125f8010a3dSEd Tanous         return;
126f8010a3dSEd Tanous     }
127f8010a3dSEd Tanous     if (swInvPurpose == nullptr || *swInvPurpose != swVersionPurpose)
128f8010a3dSEd Tanous     {
129f8010a3dSEd Tanous         // Not purpose we're looking for
130f8010a3dSEd Tanous         return;
131f8010a3dSEd Tanous     }
132f8010a3dSEd Tanous 
133f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image ID: {}", swId);
134f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Running image: {}", runningImage);
135f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose);
136f8010a3dSEd Tanous 
137f8010a3dSEd Tanous     if (populateLinkToImages)
138f8010a3dSEd Tanous     {
139f8010a3dSEd Tanous         nlohmann::json& softwareImageMembers =
140f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["SoftwareImages"];
141f8010a3dSEd Tanous         // Firmware images are at
142f8010a3dSEd Tanous         // /redfish/v1/UpdateService/FirmwareInventory/<Id>
143f8010a3dSEd Tanous         // e.g. .../FirmwareInventory/82d3ec86
144f8010a3dSEd Tanous         nlohmann::json::object_t member;
145f8010a3dSEd Tanous         member["@odata.id"] = boost::urls::format(
146f8010a3dSEd Tanous             "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
147f8010a3dSEd Tanous         softwareImageMembers.emplace_back(std::move(member));
148f8010a3dSEd Tanous         asyncResp->res.jsonValue["Links"]["SoftwareImages@odata.count"] =
149f8010a3dSEd Tanous             softwareImageMembers.size();
150f8010a3dSEd Tanous 
151f8010a3dSEd Tanous         if (runningImage)
152f8010a3dSEd Tanous         {
153f8010a3dSEd Tanous             nlohmann::json::object_t runningMember;
154f8010a3dSEd Tanous             runningMember["@odata.id"] = boost::urls::format(
155f8010a3dSEd Tanous                 "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
156f8010a3dSEd Tanous             // Create the link to the running image
157f8010a3dSEd Tanous             asyncResp->res.jsonValue["Links"]["ActiveSoftwareImage"] =
158f8010a3dSEd Tanous                 std::move(runningMember);
159f8010a3dSEd Tanous         }
160f8010a3dSEd Tanous     }
161f8010a3dSEd Tanous     if (!activeVersionPropName.empty() && runningImage)
162f8010a3dSEd Tanous     {
163*fa712405SDaniel Hsu         if (version->empty())
164*fa712405SDaniel Hsu         {
165*fa712405SDaniel Hsu             BMCWEB_LOG_INFO("Version is empty for swId: {}", swId);
166*fa712405SDaniel Hsu             return;
167*fa712405SDaniel Hsu         }
168f8010a3dSEd Tanous         asyncResp->res.jsonValue[activeVersionPropName] = *version;
169f8010a3dSEd Tanous     }
170f8010a3dSEd Tanous }
171f8010a3dSEd Tanous 
172f8010a3dSEd Tanous inline void afterGetSubtree(
173f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
174f8010a3dSEd Tanous     const std::string& swVersionPurpose,
175f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
176f8010a3dSEd Tanous     const std::vector<std::string>& functionalSwIds,
177f8010a3dSEd Tanous     const boost::system::error_code& ec,
178f8010a3dSEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
179f8010a3dSEd Tanous {
180f8010a3dSEd Tanous     if (ec)
181f8010a3dSEd Tanous     {
182fd4f088fSMyung Bae         if (ec.value() != EBADR)
183fd4f088fSMyung Bae         {
184f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("error_code = {}", ec);
185f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
186fd4f088fSMyung Bae         }
187f8010a3dSEd Tanous         return;
188f8010a3dSEd Tanous     }
189f8010a3dSEd Tanous 
190f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
191f8010a3dSEd Tanous 
192f8010a3dSEd Tanous     for (const std::pair<
193f8010a3dSEd Tanous              std::string,
194f8010a3dSEd Tanous              std::vector<std::pair<std::string, std::vector<std::string>>>>&
195f8010a3dSEd Tanous              obj : subtree)
196f8010a3dSEd Tanous     {
197f8010a3dSEd Tanous         sdbusplus::message::object_path path(obj.first);
198f8010a3dSEd Tanous         std::string swId = path.filename();
199f8010a3dSEd Tanous         if (swId.empty())
200f8010a3dSEd Tanous         {
201f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
202f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("Invalid software ID");
203f8010a3dSEd Tanous 
204f8010a3dSEd Tanous             return;
205f8010a3dSEd Tanous         }
206f8010a3dSEd Tanous 
207f8010a3dSEd Tanous         bool runningImage = false;
208f8010a3dSEd Tanous         // Look at Ids from
209f8010a3dSEd Tanous         // /xyz/openbmc_project/software/functional
210f8010a3dSEd Tanous         // to determine if this is
211f8010a3dSEd Tanous         // a running image
212f8010a3dSEd Tanous         if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end())
213f8010a3dSEd Tanous         {
214f8010a3dSEd Tanous             runningImage = true;
215f8010a3dSEd Tanous         }
216f8010a3dSEd Tanous 
217f8010a3dSEd Tanous         // Now grab its version
218f8010a3dSEd Tanous         // info
219deae6a78SEd Tanous         dbus::utility::getAllProperties(
220f8010a3dSEd Tanous             *crow::connections::systemBus, obj.second[0].first, obj.first,
221f8010a3dSEd Tanous             "xyz.openbmc_project.Software.Version",
222f8010a3dSEd Tanous             [asyncResp, swId, runningImage, swVersionPurpose,
223f8010a3dSEd Tanous              activeVersionPropName, populateLinkToImages](
224f8010a3dSEd Tanous                 const boost::system::error_code& ec3,
225f8010a3dSEd Tanous                 const dbus::utility::DBusPropertiesMap& propertiesList) {
226f8010a3dSEd Tanous                 afterGetProperties(asyncResp, swId, runningImage,
227f8010a3dSEd Tanous                                    swVersionPurpose, activeVersionPropName,
228f8010a3dSEd Tanous                                    populateLinkToImages, ec3, propertiesList);
229f8010a3dSEd Tanous             });
230f8010a3dSEd Tanous     }
231f8010a3dSEd Tanous }
232f8010a3dSEd Tanous 
233f8010a3dSEd Tanous inline void afterAssociatedEndpoints(
234f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
235f8010a3dSEd Tanous     const std::string& swVersionPurpose,
236f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
237f8010a3dSEd Tanous     const boost::system::error_code& ec,
238f8010a3dSEd Tanous     const dbus::utility::MapperEndPoints& functionalSw)
239f8010a3dSEd Tanous {
240f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
241f8010a3dSEd Tanous     if (ec)
242f8010a3dSEd Tanous     {
243a5f87d48SGunnar Mills         BMCWEB_LOG_DEBUG("error_code = {}", ec);
244f8010a3dSEd Tanous         // No functional software for this swVersionPurpose, so just
245f8010a3dSEd Tanous         return;
246f8010a3dSEd Tanous     }
247f8010a3dSEd Tanous 
248f8010a3dSEd Tanous     if (functionalSw.empty())
249f8010a3dSEd Tanous     {
250f8010a3dSEd Tanous         // Could keep going and try to populate SoftwareImages
251f8010a3dSEd Tanous         // but something is seriously wrong, so just fail
252f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("Zero functional software in system");
253f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
254f8010a3dSEd Tanous         return;
255f8010a3dSEd Tanous     }
256f8010a3dSEd Tanous 
257f8010a3dSEd Tanous     std::vector<std::string> functionalSwIds;
258f8010a3dSEd Tanous     // example functionalSw:
259f8010a3dSEd Tanous     // v as 2 "/xyz/openbmc_project/software/ace821ef"
260f8010a3dSEd Tanous     //        "/xyz/openbmc_project/software/230fb078"
261f8010a3dSEd Tanous     for (const auto& sw : functionalSw)
262f8010a3dSEd Tanous     {
263f8010a3dSEd Tanous         sdbusplus::message::object_path path(sw);
264f8010a3dSEd Tanous         std::string leaf = path.filename();
265f8010a3dSEd Tanous         if (leaf.empty())
266f8010a3dSEd Tanous         {
267f8010a3dSEd Tanous             continue;
268f8010a3dSEd Tanous         }
269f8010a3dSEd Tanous 
270f8010a3dSEd Tanous         functionalSwIds.push_back(leaf);
271f8010a3dSEd Tanous     }
272f8010a3dSEd Tanous 
273f8010a3dSEd Tanous     constexpr std::array<std::string_view, 1> interfaces = {
274f8010a3dSEd Tanous         "xyz.openbmc_project.Software.Version"};
275f8010a3dSEd Tanous     dbus::utility::getSubTree(
276f8010a3dSEd Tanous         "/xyz/openbmc_project/software", 0, interfaces,
277f8010a3dSEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
278f8010a3dSEd Tanous          populateLinkToImages, functionalSwIds](
279f8010a3dSEd Tanous             const boost::system::error_code& ec2,
280f8010a3dSEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
281f8010a3dSEd Tanous             afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName,
282f8010a3dSEd Tanous                             populateLinkToImages, functionalSwIds, ec2,
283f8010a3dSEd Tanous                             subtree);
284f8010a3dSEd Tanous         });
285f8010a3dSEd Tanous }
286f8010a3dSEd Tanous 
287eee0013eSWilly Tu /**
288eee0013eSWilly Tu  * @brief Populate the running software version and image links
289eee0013eSWilly Tu  *
290ac106bf6SEd Tanous  * @param[i,o] asyncResp             Async response object
291eee0013eSWilly Tu  * @param[i]   swVersionPurpose  Indicates what target to look for
292ac106bf6SEd Tanous  * @param[i]   activeVersionPropName  Index in asyncResp->res.jsonValue to write
293eee0013eSWilly Tu  * the running software version to
294ac106bf6SEd Tanous  * @param[i]   populateLinkToImages  Populate asyncResp->res "Links"
295eee0013eSWilly Tu  * "ActiveSoftwareImage" with a link to the running software image and
296eee0013eSWilly Tu  * "SoftwareImages" with a link to the all its software images
297eee0013eSWilly Tu  *
298eee0013eSWilly Tu  * @return void
299eee0013eSWilly Tu  */
300ac106bf6SEd Tanous inline void populateSoftwareInformation(
301ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
302eee0013eSWilly Tu     const std::string& swVersionPurpose,
303ac106bf6SEd Tanous     const std::string& activeVersionPropName, const bool populateLinkToImages)
304eee0013eSWilly Tu {
3057f23576aSJagpal Singh Gill     auto swPath = getFunctionalSoftwarePath(swVersionPurpose);
3067f23576aSJagpal Singh Gill     if (!swPath)
3077f23576aSJagpal Singh Gill     {
3087f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("Invalid software type");
3097f23576aSJagpal Singh Gill         messages::internalError(asyncResp->res);
3107f23576aSJagpal Singh Gill         return;
3117f23576aSJagpal Singh Gill     }
312eee0013eSWilly Tu     // Used later to determine running (known on Redfish as active) Sw images
313a4eb761aSGeorge Liu     dbus::utility::getAssociationEndPoints(
3147f23576aSJagpal Singh Gill         swPath.value().str,
315ac106bf6SEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
316ac106bf6SEd Tanous          populateLinkToImages](
317a4eb761aSGeorge Liu             const boost::system::error_code& ec,
318a4eb761aSGeorge Liu             const dbus::utility::MapperEndPoints& functionalSw) {
319f8010a3dSEd Tanous             afterAssociatedEndpoints(asyncResp, swVersionPurpose,
320f8010a3dSEd Tanous                                      activeVersionPropName,
321f8010a3dSEd Tanous                                      populateLinkToImages, ec, functionalSw);
322eee0013eSWilly Tu         });
323eee0013eSWilly Tu }
324eee0013eSWilly Tu 
325eee0013eSWilly Tu /**
326eee0013eSWilly Tu  * @brief Translate input swState to Redfish state
327eee0013eSWilly Tu  *
328eee0013eSWilly Tu  * This function will return the corresponding Redfish state
329eee0013eSWilly Tu  *
330eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
331eee0013eSWilly Tu  *
332eee0013eSWilly Tu  * @return The corresponding Redfish state
333eee0013eSWilly Tu  */
3340ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState)
335eee0013eSWilly Tu {
336eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active")
337eee0013eSWilly Tu     {
3380ec8b83dSEd Tanous         return resource::State::Enabled;
339eee0013eSWilly Tu     }
340eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
341eee0013eSWilly Tu                    "Activations.Activating")
342eee0013eSWilly Tu     {
3430ec8b83dSEd Tanous         return resource::State::Updating;
344eee0013eSWilly Tu     }
345eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
346eee0013eSWilly Tu                    "Activations.StandbySpare")
347eee0013eSWilly Tu     {
3480ec8b83dSEd Tanous         return resource::State::StandbySpare;
349eee0013eSWilly Tu     }
35062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Default sw state {} to Disabled", swState);
3510ec8b83dSEd Tanous     return resource::State::Disabled;
352eee0013eSWilly Tu }
353eee0013eSWilly Tu 
354eee0013eSWilly Tu /**
355eee0013eSWilly Tu  * @brief Translate input swState to Redfish health state
356eee0013eSWilly Tu  *
357eee0013eSWilly Tu  * This function will return the corresponding Redfish health state
358eee0013eSWilly Tu  *
359eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
360eee0013eSWilly Tu  *
361eee0013eSWilly Tu  * @return The corresponding Redfish health state
362eee0013eSWilly Tu  */
363eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState)
364eee0013eSWilly Tu {
365eee0013eSWilly Tu     if ((swState ==
366eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Active") ||
367eee0013eSWilly Tu         (swState == "xyz.openbmc_project.Software.Activation.Activations."
368eee0013eSWilly Tu                     "Activating") ||
369eee0013eSWilly Tu         (swState ==
370eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Ready"))
371eee0013eSWilly Tu     {
372eee0013eSWilly Tu         return "OK";
373eee0013eSWilly Tu     }
37462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sw state {} to Warning", swState);
375eee0013eSWilly Tu     return "Warning";
376eee0013eSWilly Tu }
377eee0013eSWilly Tu 
378eee0013eSWilly Tu /**
379c9bd0924SGunnar Mills  * @brief Put LowestSupportedVersion of input swId into json response
380c9bd0924SGunnar Mills  *
381c9bd0924SGunnar Mills  * This function will put the MinimumVersion from D-Bus of the input
382c9bd0924SGunnar Mills  * software id to ["LowestSupportedVersion"].
383c9bd0924SGunnar Mills  *
384c9bd0924SGunnar Mills  * @param[i,o] asyncResp    Async response object
385c9bd0924SGunnar Mills  * @param[i] swId The software ID to get Minimum Version for
386c9bd0924SGunnar Mills  * @param[i]   dbusSvc  The dbus service implementing the software object
387c9bd0924SGunnar Mills  *
388c9bd0924SGunnar Mills  * @return void
389c9bd0924SGunnar Mills  */
390c9bd0924SGunnar Mills inline void getSwMinimumVersion(
391c9bd0924SGunnar Mills     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
392c9bd0924SGunnar Mills     const std::shared_ptr<std::string>& swId, const std::string& dbusSvc)
393c9bd0924SGunnar Mills {
394c9bd0924SGunnar Mills     BMCWEB_LOG_DEBUG("getSwMinimumVersion: svc {}, swId {}", dbusSvc, *swId);
395c9bd0924SGunnar Mills 
396c9bd0924SGunnar Mills     sdbusplus::message::object_path path("/xyz/openbmc_project/software");
397c9bd0924SGunnar Mills     path /= *swId;
398c9bd0924SGunnar Mills 
399c9bd0924SGunnar Mills     dbus::utility::getProperty<std::string>(
400c9bd0924SGunnar Mills         dbusSvc, path, "xyz.openbmc_project.Software.MinimumVersion",
401c9bd0924SGunnar Mills         "MinimumVersion",
402c9bd0924SGunnar Mills         [asyncResp](const boost::system::error_code& ec,
403c9bd0924SGunnar Mills                     const std::string& swMinimumVersion) {
404c9bd0924SGunnar Mills             if (ec)
405c9bd0924SGunnar Mills             {
406c9bd0924SGunnar Mills                 // not all software has this interface and it is not critical
407c9bd0924SGunnar Mills                 return;
408c9bd0924SGunnar Mills             }
409c9bd0924SGunnar Mills 
410c9bd0924SGunnar Mills             BMCWEB_LOG_DEBUG("getSwMinimumVersion: MinimumVersion {}",
411c9bd0924SGunnar Mills                              swMinimumVersion);
412c9bd0924SGunnar Mills 
413c9bd0924SGunnar Mills             asyncResp->res.jsonValue["LowestSupportedVersion"] =
414c9bd0924SGunnar Mills                 swMinimumVersion;
415c9bd0924SGunnar Mills         });
416c9bd0924SGunnar Mills }
417c9bd0924SGunnar Mills 
418c9bd0924SGunnar Mills /**
419eee0013eSWilly Tu  * @brief Put status of input swId into json response
420eee0013eSWilly Tu  *
421eee0013eSWilly Tu  * This function will put the appropriate Redfish state of the input
422eee0013eSWilly Tu  * software id to ["Status"]["State"] within the json response
423eee0013eSWilly Tu  *
424ac106bf6SEd Tanous  * @param[i,o] asyncResp    Async response object
425eee0013eSWilly Tu  * @param[i]   swId     The software ID to get status for
426eee0013eSWilly Tu  * @param[i]   dbusSvc  The dbus service implementing the software object
427eee0013eSWilly Tu  *
428eee0013eSWilly Tu  * @return void
429eee0013eSWilly Tu  */
430eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
431eee0013eSWilly Tu                         const std::shared_ptr<std::string>& swId,
432eee0013eSWilly Tu                         const std::string& dbusSvc)
433eee0013eSWilly Tu {
43462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSwStatus: swId {} svc {}", *swId, dbusSvc);
435eee0013eSWilly Tu 
436deae6a78SEd Tanous     dbus::utility::getAllProperties(
437deae6a78SEd Tanous         dbusSvc, "/xyz/openbmc_project/software/" + *swId,
438d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Activation",
439eee0013eSWilly Tu         [asyncResp,
4408b24275dSEd Tanous          swId](const boost::system::error_code& ec,
441eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
4428b24275dSEd Tanous             if (ec)
443eee0013eSWilly Tu             {
444eee0013eSWilly Tu                 // not all swtypes are updateable, this is ok
445539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
446539d8c6bSEd Tanous                     resource::State::Enabled;
447eee0013eSWilly Tu                 return;
448eee0013eSWilly Tu             }
449d1bde9e5SKrzysztof Grobelny 
450eee0013eSWilly Tu             const std::string* swInvActivation = nullptr;
451d1bde9e5SKrzysztof Grobelny 
452d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
453d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation",
454d1bde9e5SKrzysztof Grobelny                 swInvActivation);
455d1bde9e5SKrzysztof Grobelny 
456d1bde9e5SKrzysztof Grobelny             if (!success)
457eee0013eSWilly Tu             {
458d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
459d1bde9e5SKrzysztof Grobelny                 return;
460eee0013eSWilly Tu             }
461eee0013eSWilly Tu 
462eee0013eSWilly Tu             if (swInvActivation == nullptr)
463eee0013eSWilly Tu             {
464eee0013eSWilly Tu                 messages::internalError(asyncResp->res);
465eee0013eSWilly Tu                 return;
466eee0013eSWilly Tu             }
467d1bde9e5SKrzysztof Grobelny 
46862598e31SEd Tanous             BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation);
469eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] =
470eee0013eSWilly Tu                 getRedfishSwState(*swInvActivation);
471eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["Health"] =
472eee0013eSWilly Tu                 getRedfishSwHealth(*swInvActivation);
473d1bde9e5SKrzysztof Grobelny         });
474eee0013eSWilly Tu }
475eee0013eSWilly Tu 
476c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints(
477c018f705SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
478c018f705SJagpal Singh Gill     const std::shared_ptr<std::string>& swId,
479c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
480c018f705SJagpal Singh Gill     const dbus::utility::MapperEndPoints& objPaths)
481c018f705SJagpal Singh Gill {
482c018f705SJagpal Singh Gill     if (ec)
483c018f705SJagpal Singh Gill     {
484c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
485c018f705SJagpal Singh Gill         // System can exist with no updateable software,
486c018f705SJagpal Singh Gill         // so don't throw error here.
487c018f705SJagpal Singh Gill         return;
488c018f705SJagpal Singh Gill     }
489c018f705SJagpal Singh Gill     sdbusplus::message::object_path reqSwObjPath(
490c018f705SJagpal Singh Gill         "/xyz/openbmc_project/software");
491c018f705SJagpal Singh Gill     reqSwObjPath = reqSwObjPath / *swId;
492c018f705SJagpal Singh Gill 
493c018f705SJagpal Singh Gill     if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end())
494c018f705SJagpal Singh Gill     {
495c018f705SJagpal Singh Gill         asyncResp->res.jsonValue["Updateable"] = true;
496c018f705SJagpal Singh Gill         return;
497c018f705SJagpal Singh Gill     }
498c018f705SJagpal Singh Gill }
499c018f705SJagpal Singh Gill 
500504af5a0SPatrick Williams inline void handleUpdateableObject(
501504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
502c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
503c018f705SJagpal Singh Gill     const dbus::utility::MapperGetObject& objectInfo)
504c018f705SJagpal Singh Gill {
505c018f705SJagpal Singh Gill     if (ec)
506c018f705SJagpal Singh Gill     {
507c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
508c018f705SJagpal Singh Gill         // System can exist with no updateable software,
509c018f705SJagpal Singh Gill         // so don't throw error here.
510c018f705SJagpal Singh Gill         return;
511c018f705SJagpal Singh Gill     }
512c018f705SJagpal Singh Gill     if (objectInfo.empty())
513c018f705SJagpal Singh Gill     {
514c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG("No updateable software found");
515c018f705SJagpal Singh Gill         // System can exist with no updateable software,
516c018f705SJagpal Singh Gill         // so don't throw error here.
517c018f705SJagpal Singh Gill         return;
518c018f705SJagpal Singh Gill     }
519c018f705SJagpal Singh Gill     asyncResp->res.jsonValue["Updateable"] = true;
520c018f705SJagpal Singh Gill }
521c018f705SJagpal Singh Gill 
522eee0013eSWilly Tu /**
523eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
524eee0013eSWilly Tu  *
525eee0013eSWilly Tu  * This function checks whether software inventory component
526eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
527eee0013eSWilly Tu  * Property.
528eee0013eSWilly Tu  *
529eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
530eee0013eSWilly Tu  * @param[i]   swId       The software ID
531eee0013eSWilly Tu  */
532504af5a0SPatrick Williams inline void getSwUpdatableStatus(
533504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
534eee0013eSWilly Tu     const std::shared_ptr<std::string>& swId)
535eee0013eSWilly Tu {
536c018f705SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
537c018f705SJagpal Singh Gill     {
538c018f705SJagpal Singh Gill         sdbusplus::message::object_path swObjectPath(
539c018f705SJagpal Singh Gill             "/xyz/openbmc_project/software");
540c018f705SJagpal Singh Gill         swObjectPath = swObjectPath / *swId;
541c018f705SJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
542c018f705SJagpal Singh Gill             "xyz.openbmc_project.Software.Update"};
543c018f705SJagpal Singh Gill         dbus::utility::getDbusObject(
544c018f705SJagpal Singh Gill             swObjectPath.str, interfaces,
545c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableObject, asyncResp));
546c018f705SJagpal Singh Gill     }
547c018f705SJagpal Singh Gill     else
548c018f705SJagpal Singh Gill     {
5496c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
550eee0013eSWilly Tu             "/xyz/openbmc_project/software/updateable",
551c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableEndpoints, asyncResp, swId));
552eee0013eSWilly Tu     }
553eee0013eSWilly Tu }
554eee0013eSWilly Tu 
555eee0013eSWilly Tu } // namespace sw_util
556eee0013eSWilly Tu } // namespace redfish
557