xref: /openbmc/bmcweb/features/redfish/include/utils/sw_utils.hpp (revision c9bd09240cfa156ca348848ad6402b1d390bbfa1)
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 
122f8010a3dSEd Tanous     if (version == nullptr || version->empty())
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     {
163f8010a3dSEd Tanous         asyncResp->res.jsonValue[activeVersionPropName] = *version;
164f8010a3dSEd Tanous     }
165f8010a3dSEd Tanous }
166f8010a3dSEd Tanous 
167f8010a3dSEd Tanous inline void afterGetSubtree(
168f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
169f8010a3dSEd Tanous     const std::string& swVersionPurpose,
170f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
171f8010a3dSEd Tanous     const std::vector<std::string>& functionalSwIds,
172f8010a3dSEd Tanous     const boost::system::error_code& ec,
173f8010a3dSEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
174f8010a3dSEd Tanous {
175f8010a3dSEd Tanous     if (ec)
176f8010a3dSEd Tanous     {
177fd4f088fSMyung Bae         if (ec.value() != EBADR)
178fd4f088fSMyung Bae         {
179f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("error_code = {}", ec);
180f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
181fd4f088fSMyung Bae         }
182f8010a3dSEd Tanous         return;
183f8010a3dSEd Tanous     }
184f8010a3dSEd Tanous 
185f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
186f8010a3dSEd Tanous 
187f8010a3dSEd Tanous     for (const std::pair<
188f8010a3dSEd Tanous              std::string,
189f8010a3dSEd Tanous              std::vector<std::pair<std::string, std::vector<std::string>>>>&
190f8010a3dSEd Tanous              obj : subtree)
191f8010a3dSEd Tanous     {
192f8010a3dSEd Tanous         sdbusplus::message::object_path path(obj.first);
193f8010a3dSEd Tanous         std::string swId = path.filename();
194f8010a3dSEd Tanous         if (swId.empty())
195f8010a3dSEd Tanous         {
196f8010a3dSEd Tanous             messages::internalError(asyncResp->res);
197f8010a3dSEd Tanous             BMCWEB_LOG_ERROR("Invalid software ID");
198f8010a3dSEd Tanous 
199f8010a3dSEd Tanous             return;
200f8010a3dSEd Tanous         }
201f8010a3dSEd Tanous 
202f8010a3dSEd Tanous         bool runningImage = false;
203f8010a3dSEd Tanous         // Look at Ids from
204f8010a3dSEd Tanous         // /xyz/openbmc_project/software/functional
205f8010a3dSEd Tanous         // to determine if this is
206f8010a3dSEd Tanous         // a running image
207f8010a3dSEd Tanous         if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end())
208f8010a3dSEd Tanous         {
209f8010a3dSEd Tanous             runningImage = true;
210f8010a3dSEd Tanous         }
211f8010a3dSEd Tanous 
212f8010a3dSEd Tanous         // Now grab its version
213f8010a3dSEd Tanous         // info
214deae6a78SEd Tanous         dbus::utility::getAllProperties(
215f8010a3dSEd Tanous             *crow::connections::systemBus, obj.second[0].first, obj.first,
216f8010a3dSEd Tanous             "xyz.openbmc_project.Software.Version",
217f8010a3dSEd Tanous             [asyncResp, swId, runningImage, swVersionPurpose,
218f8010a3dSEd Tanous              activeVersionPropName, populateLinkToImages](
219f8010a3dSEd Tanous                 const boost::system::error_code& ec3,
220f8010a3dSEd Tanous                 const dbus::utility::DBusPropertiesMap& propertiesList) {
221f8010a3dSEd Tanous                 afterGetProperties(asyncResp, swId, runningImage,
222f8010a3dSEd Tanous                                    swVersionPurpose, activeVersionPropName,
223f8010a3dSEd Tanous                                    populateLinkToImages, ec3, propertiesList);
224f8010a3dSEd Tanous             });
225f8010a3dSEd Tanous     }
226f8010a3dSEd Tanous }
227f8010a3dSEd Tanous 
228f8010a3dSEd Tanous inline void afterAssociatedEndpoints(
229f8010a3dSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
230f8010a3dSEd Tanous     const std::string& swVersionPurpose,
231f8010a3dSEd Tanous     const std::string& activeVersionPropName, bool populateLinkToImages,
232f8010a3dSEd Tanous     const boost::system::error_code& ec,
233f8010a3dSEd Tanous     const dbus::utility::MapperEndPoints& functionalSw)
234f8010a3dSEd Tanous {
235f8010a3dSEd Tanous     BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
236f8010a3dSEd Tanous     if (ec)
237f8010a3dSEd Tanous     {
238a5f87d48SGunnar Mills         BMCWEB_LOG_DEBUG("error_code = {}", ec);
239f8010a3dSEd Tanous         // No functional software for this swVersionPurpose, so just
240f8010a3dSEd Tanous         return;
241f8010a3dSEd Tanous     }
242f8010a3dSEd Tanous 
243f8010a3dSEd Tanous     if (functionalSw.empty())
244f8010a3dSEd Tanous     {
245f8010a3dSEd Tanous         // Could keep going and try to populate SoftwareImages
246f8010a3dSEd Tanous         // but something is seriously wrong, so just fail
247f8010a3dSEd Tanous         BMCWEB_LOG_ERROR("Zero functional software in system");
248f8010a3dSEd Tanous         messages::internalError(asyncResp->res);
249f8010a3dSEd Tanous         return;
250f8010a3dSEd Tanous     }
251f8010a3dSEd Tanous 
252f8010a3dSEd Tanous     std::vector<std::string> functionalSwIds;
253f8010a3dSEd Tanous     // example functionalSw:
254f8010a3dSEd Tanous     // v as 2 "/xyz/openbmc_project/software/ace821ef"
255f8010a3dSEd Tanous     //        "/xyz/openbmc_project/software/230fb078"
256f8010a3dSEd Tanous     for (const auto& sw : functionalSw)
257f8010a3dSEd Tanous     {
258f8010a3dSEd Tanous         sdbusplus::message::object_path path(sw);
259f8010a3dSEd Tanous         std::string leaf = path.filename();
260f8010a3dSEd Tanous         if (leaf.empty())
261f8010a3dSEd Tanous         {
262f8010a3dSEd Tanous             continue;
263f8010a3dSEd Tanous         }
264f8010a3dSEd Tanous 
265f8010a3dSEd Tanous         functionalSwIds.push_back(leaf);
266f8010a3dSEd Tanous     }
267f8010a3dSEd Tanous 
268f8010a3dSEd Tanous     constexpr std::array<std::string_view, 1> interfaces = {
269f8010a3dSEd Tanous         "xyz.openbmc_project.Software.Version"};
270f8010a3dSEd Tanous     dbus::utility::getSubTree(
271f8010a3dSEd Tanous         "/xyz/openbmc_project/software", 0, interfaces,
272f8010a3dSEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
273f8010a3dSEd Tanous          populateLinkToImages, functionalSwIds](
274f8010a3dSEd Tanous             const boost::system::error_code& ec2,
275f8010a3dSEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
276f8010a3dSEd Tanous             afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName,
277f8010a3dSEd Tanous                             populateLinkToImages, functionalSwIds, ec2,
278f8010a3dSEd Tanous                             subtree);
279f8010a3dSEd Tanous         });
280f8010a3dSEd Tanous }
281f8010a3dSEd Tanous 
282eee0013eSWilly Tu /**
283eee0013eSWilly Tu  * @brief Populate the running software version and image links
284eee0013eSWilly Tu  *
285ac106bf6SEd Tanous  * @param[i,o] asyncResp             Async response object
286eee0013eSWilly Tu  * @param[i]   swVersionPurpose  Indicates what target to look for
287ac106bf6SEd Tanous  * @param[i]   activeVersionPropName  Index in asyncResp->res.jsonValue to write
288eee0013eSWilly Tu  * the running software version to
289ac106bf6SEd Tanous  * @param[i]   populateLinkToImages  Populate asyncResp->res "Links"
290eee0013eSWilly Tu  * "ActiveSoftwareImage" with a link to the running software image and
291eee0013eSWilly Tu  * "SoftwareImages" with a link to the all its software images
292eee0013eSWilly Tu  *
293eee0013eSWilly Tu  * @return void
294eee0013eSWilly Tu  */
295ac106bf6SEd Tanous inline void populateSoftwareInformation(
296ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
297eee0013eSWilly Tu     const std::string& swVersionPurpose,
298ac106bf6SEd Tanous     const std::string& activeVersionPropName, const bool populateLinkToImages)
299eee0013eSWilly Tu {
3007f23576aSJagpal Singh Gill     auto swPath = getFunctionalSoftwarePath(swVersionPurpose);
3017f23576aSJagpal Singh Gill     if (!swPath)
3027f23576aSJagpal Singh Gill     {
3037f23576aSJagpal Singh Gill         BMCWEB_LOG_ERROR("Invalid software type");
3047f23576aSJagpal Singh Gill         messages::internalError(asyncResp->res);
3057f23576aSJagpal Singh Gill         return;
3067f23576aSJagpal Singh Gill     }
307eee0013eSWilly Tu     // Used later to determine running (known on Redfish as active) Sw images
308a4eb761aSGeorge Liu     dbus::utility::getAssociationEndPoints(
3097f23576aSJagpal Singh Gill         swPath.value().str,
310ac106bf6SEd Tanous         [asyncResp, swVersionPurpose, activeVersionPropName,
311ac106bf6SEd Tanous          populateLinkToImages](
312a4eb761aSGeorge Liu             const boost::system::error_code& ec,
313a4eb761aSGeorge Liu             const dbus::utility::MapperEndPoints& functionalSw) {
314f8010a3dSEd Tanous             afterAssociatedEndpoints(asyncResp, swVersionPurpose,
315f8010a3dSEd Tanous                                      activeVersionPropName,
316f8010a3dSEd Tanous                                      populateLinkToImages, ec, functionalSw);
317eee0013eSWilly Tu         });
318eee0013eSWilly Tu }
319eee0013eSWilly Tu 
320eee0013eSWilly Tu /**
321eee0013eSWilly Tu  * @brief Translate input swState to Redfish state
322eee0013eSWilly Tu  *
323eee0013eSWilly Tu  * This function will return the corresponding Redfish state
324eee0013eSWilly Tu  *
325eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
326eee0013eSWilly Tu  *
327eee0013eSWilly Tu  * @return The corresponding Redfish state
328eee0013eSWilly Tu  */
3290ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState)
330eee0013eSWilly Tu {
331eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active")
332eee0013eSWilly Tu     {
3330ec8b83dSEd Tanous         return resource::State::Enabled;
334eee0013eSWilly Tu     }
335eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
336eee0013eSWilly Tu                    "Activations.Activating")
337eee0013eSWilly Tu     {
3380ec8b83dSEd Tanous         return resource::State::Updating;
339eee0013eSWilly Tu     }
340eee0013eSWilly Tu     if (swState == "xyz.openbmc_project.Software.Activation."
341eee0013eSWilly Tu                    "Activations.StandbySpare")
342eee0013eSWilly Tu     {
3430ec8b83dSEd Tanous         return resource::State::StandbySpare;
344eee0013eSWilly Tu     }
34562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Default sw state {} to Disabled", swState);
3460ec8b83dSEd Tanous     return resource::State::Disabled;
347eee0013eSWilly Tu }
348eee0013eSWilly Tu 
349eee0013eSWilly Tu /**
350eee0013eSWilly Tu  * @brief Translate input swState to Redfish health state
351eee0013eSWilly Tu  *
352eee0013eSWilly Tu  * This function will return the corresponding Redfish health state
353eee0013eSWilly Tu  *
354eee0013eSWilly Tu  * @param[i]   swState  The OpenBMC software state
355eee0013eSWilly Tu  *
356eee0013eSWilly Tu  * @return The corresponding Redfish health state
357eee0013eSWilly Tu  */
358eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState)
359eee0013eSWilly Tu {
360eee0013eSWilly Tu     if ((swState ==
361eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Active") ||
362eee0013eSWilly Tu         (swState == "xyz.openbmc_project.Software.Activation.Activations."
363eee0013eSWilly Tu                     "Activating") ||
364eee0013eSWilly Tu         (swState ==
365eee0013eSWilly Tu          "xyz.openbmc_project.Software.Activation.Activations.Ready"))
366eee0013eSWilly Tu     {
367eee0013eSWilly Tu         return "OK";
368eee0013eSWilly Tu     }
36962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Sw state {} to Warning", swState);
370eee0013eSWilly Tu     return "Warning";
371eee0013eSWilly Tu }
372eee0013eSWilly Tu 
373eee0013eSWilly Tu /**
374*c9bd0924SGunnar Mills  * @brief Put LowestSupportedVersion of input swId into json response
375*c9bd0924SGunnar Mills  *
376*c9bd0924SGunnar Mills  * This function will put the MinimumVersion from D-Bus of the input
377*c9bd0924SGunnar Mills  * software id to ["LowestSupportedVersion"].
378*c9bd0924SGunnar Mills  *
379*c9bd0924SGunnar Mills  * @param[i,o] asyncResp    Async response object
380*c9bd0924SGunnar Mills  * @param[i] swId The software ID to get Minimum Version for
381*c9bd0924SGunnar Mills  * @param[i]   dbusSvc  The dbus service implementing the software object
382*c9bd0924SGunnar Mills  *
383*c9bd0924SGunnar Mills  * @return void
384*c9bd0924SGunnar Mills  */
385*c9bd0924SGunnar Mills inline void getSwMinimumVersion(
386*c9bd0924SGunnar Mills     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
387*c9bd0924SGunnar Mills     const std::shared_ptr<std::string>& swId, const std::string& dbusSvc)
388*c9bd0924SGunnar Mills {
389*c9bd0924SGunnar Mills     BMCWEB_LOG_DEBUG("getSwMinimumVersion: svc {}, swId {}", dbusSvc, *swId);
390*c9bd0924SGunnar Mills 
391*c9bd0924SGunnar Mills     sdbusplus::message::object_path path("/xyz/openbmc_project/software");
392*c9bd0924SGunnar Mills     path /= *swId;
393*c9bd0924SGunnar Mills 
394*c9bd0924SGunnar Mills     dbus::utility::getProperty<std::string>(
395*c9bd0924SGunnar Mills         dbusSvc, path, "xyz.openbmc_project.Software.MinimumVersion",
396*c9bd0924SGunnar Mills         "MinimumVersion",
397*c9bd0924SGunnar Mills         [asyncResp](const boost::system::error_code& ec,
398*c9bd0924SGunnar Mills                     const std::string& swMinimumVersion) {
399*c9bd0924SGunnar Mills             if (ec)
400*c9bd0924SGunnar Mills             {
401*c9bd0924SGunnar Mills                 // not all software has this interface and it is not critical
402*c9bd0924SGunnar Mills                 return;
403*c9bd0924SGunnar Mills             }
404*c9bd0924SGunnar Mills 
405*c9bd0924SGunnar Mills             BMCWEB_LOG_DEBUG("getSwMinimumVersion: MinimumVersion {}",
406*c9bd0924SGunnar Mills                              swMinimumVersion);
407*c9bd0924SGunnar Mills 
408*c9bd0924SGunnar Mills             asyncResp->res.jsonValue["LowestSupportedVersion"] =
409*c9bd0924SGunnar Mills                 swMinimumVersion;
410*c9bd0924SGunnar Mills         });
411*c9bd0924SGunnar Mills }
412*c9bd0924SGunnar Mills 
413*c9bd0924SGunnar Mills /**
414eee0013eSWilly Tu  * @brief Put status of input swId into json response
415eee0013eSWilly Tu  *
416eee0013eSWilly Tu  * This function will put the appropriate Redfish state of the input
417eee0013eSWilly Tu  * software id to ["Status"]["State"] within the json response
418eee0013eSWilly Tu  *
419ac106bf6SEd Tanous  * @param[i,o] asyncResp    Async response object
420eee0013eSWilly Tu  * @param[i]   swId     The software ID to get status for
421eee0013eSWilly Tu  * @param[i]   dbusSvc  The dbus service implementing the software object
422eee0013eSWilly Tu  *
423eee0013eSWilly Tu  * @return void
424eee0013eSWilly Tu  */
425eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
426eee0013eSWilly Tu                         const std::shared_ptr<std::string>& swId,
427eee0013eSWilly Tu                         const std::string& dbusSvc)
428eee0013eSWilly Tu {
42962598e31SEd Tanous     BMCWEB_LOG_DEBUG("getSwStatus: swId {} svc {}", *swId, dbusSvc);
430eee0013eSWilly Tu 
431deae6a78SEd Tanous     dbus::utility::getAllProperties(
432deae6a78SEd Tanous         dbusSvc, "/xyz/openbmc_project/software/" + *swId,
433d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Activation",
434eee0013eSWilly Tu         [asyncResp,
4358b24275dSEd Tanous          swId](const boost::system::error_code& ec,
436eee0013eSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
4378b24275dSEd Tanous             if (ec)
438eee0013eSWilly Tu             {
439eee0013eSWilly Tu                 // not all swtypes are updateable, this is ok
440539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
441539d8c6bSEd Tanous                     resource::State::Enabled;
442eee0013eSWilly Tu                 return;
443eee0013eSWilly Tu             }
444d1bde9e5SKrzysztof Grobelny 
445eee0013eSWilly Tu             const std::string* swInvActivation = nullptr;
446d1bde9e5SKrzysztof Grobelny 
447d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
448d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation",
449d1bde9e5SKrzysztof Grobelny                 swInvActivation);
450d1bde9e5SKrzysztof Grobelny 
451d1bde9e5SKrzysztof Grobelny             if (!success)
452eee0013eSWilly Tu             {
453d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
454d1bde9e5SKrzysztof Grobelny                 return;
455eee0013eSWilly Tu             }
456eee0013eSWilly Tu 
457eee0013eSWilly Tu             if (swInvActivation == nullptr)
458eee0013eSWilly Tu             {
459eee0013eSWilly Tu                 messages::internalError(asyncResp->res);
460eee0013eSWilly Tu                 return;
461eee0013eSWilly Tu             }
462d1bde9e5SKrzysztof Grobelny 
46362598e31SEd Tanous             BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation);
464eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["State"] =
465eee0013eSWilly Tu                 getRedfishSwState(*swInvActivation);
466eee0013eSWilly Tu             asyncResp->res.jsonValue["Status"]["Health"] =
467eee0013eSWilly Tu                 getRedfishSwHealth(*swInvActivation);
468d1bde9e5SKrzysztof Grobelny         });
469eee0013eSWilly Tu }
470eee0013eSWilly Tu 
471c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints(
472c018f705SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
473c018f705SJagpal Singh Gill     const std::shared_ptr<std::string>& swId,
474c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
475c018f705SJagpal Singh Gill     const dbus::utility::MapperEndPoints& objPaths)
476c018f705SJagpal Singh Gill {
477c018f705SJagpal Singh Gill     if (ec)
478c018f705SJagpal Singh Gill     {
479c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
480c018f705SJagpal Singh Gill         // System can exist with no updateable software,
481c018f705SJagpal Singh Gill         // so don't throw error here.
482c018f705SJagpal Singh Gill         return;
483c018f705SJagpal Singh Gill     }
484c018f705SJagpal Singh Gill     sdbusplus::message::object_path reqSwObjPath(
485c018f705SJagpal Singh Gill         "/xyz/openbmc_project/software");
486c018f705SJagpal Singh Gill     reqSwObjPath = reqSwObjPath / *swId;
487c018f705SJagpal Singh Gill 
488c018f705SJagpal Singh Gill     if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end())
489c018f705SJagpal Singh Gill     {
490c018f705SJagpal Singh Gill         asyncResp->res.jsonValue["Updateable"] = true;
491c018f705SJagpal Singh Gill         return;
492c018f705SJagpal Singh Gill     }
493c018f705SJagpal Singh Gill }
494c018f705SJagpal Singh Gill 
495504af5a0SPatrick Williams inline void handleUpdateableObject(
496504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
497c018f705SJagpal Singh Gill     const boost::system::error_code& ec,
498c018f705SJagpal Singh Gill     const dbus::utility::MapperGetObject& objectInfo)
499c018f705SJagpal Singh Gill {
500c018f705SJagpal Singh Gill     if (ec)
501c018f705SJagpal Singh Gill     {
502c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG(" error_code = {} error msg =  {}", ec, ec.message());
503c018f705SJagpal Singh Gill         // System can exist with no updateable software,
504c018f705SJagpal Singh Gill         // so don't throw error here.
505c018f705SJagpal Singh Gill         return;
506c018f705SJagpal Singh Gill     }
507c018f705SJagpal Singh Gill     if (objectInfo.empty())
508c018f705SJagpal Singh Gill     {
509c018f705SJagpal Singh Gill         BMCWEB_LOG_DEBUG("No updateable software found");
510c018f705SJagpal Singh Gill         // System can exist with no updateable software,
511c018f705SJagpal Singh Gill         // so don't throw error here.
512c018f705SJagpal Singh Gill         return;
513c018f705SJagpal Singh Gill     }
514c018f705SJagpal Singh Gill     asyncResp->res.jsonValue["Updateable"] = true;
515c018f705SJagpal Singh Gill }
516c018f705SJagpal Singh Gill 
517eee0013eSWilly Tu /**
518eee0013eSWilly Tu  * @brief Updates programmable status of input swId into json response
519eee0013eSWilly Tu  *
520eee0013eSWilly Tu  * This function checks whether software inventory component
521eee0013eSWilly Tu  * can be programmable or not and fill's the "Updatable"
522eee0013eSWilly Tu  * Property.
523eee0013eSWilly Tu  *
524eee0013eSWilly Tu  * @param[i,o] asyncResp  Async response object
525eee0013eSWilly Tu  * @param[i]   swId       The software ID
526eee0013eSWilly Tu  */
527504af5a0SPatrick Williams inline void getSwUpdatableStatus(
528504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
529eee0013eSWilly Tu     const std::shared_ptr<std::string>& swId)
530eee0013eSWilly Tu {
531c018f705SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
532c018f705SJagpal Singh Gill     {
533c018f705SJagpal Singh Gill         sdbusplus::message::object_path swObjectPath(
534c018f705SJagpal Singh Gill             "/xyz/openbmc_project/software");
535c018f705SJagpal Singh Gill         swObjectPath = swObjectPath / *swId;
536c018f705SJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
537c018f705SJagpal Singh Gill             "xyz.openbmc_project.Software.Update"};
538c018f705SJagpal Singh Gill         dbus::utility::getDbusObject(
539c018f705SJagpal Singh Gill             swObjectPath.str, interfaces,
540c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableObject, asyncResp));
541c018f705SJagpal Singh Gill     }
542c018f705SJagpal Singh Gill     else
543c018f705SJagpal Singh Gill     {
5446c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
545eee0013eSWilly Tu             "/xyz/openbmc_project/software/updateable",
546c018f705SJagpal Singh Gill             std::bind_front(handleUpdateableEndpoints, asyncResp, swId));
547eee0013eSWilly Tu     }
548eee0013eSWilly Tu }
549eee0013eSWilly Tu 
550eee0013eSWilly Tu } // namespace sw_util
551eee0013eSWilly Tu } // namespace redfish
552