Firmware: Add ActiveSoftwareImage for the running image

ActiveSoftwareImage was added to Bios in v1_1_0 and Manager in v1_6_0.

What Redfish calls active is the functional or running image in
OpenBMC.

Reused getActiveFwVersion which means less D-Bus calls when
calling from Manager.

From https://redfish.dmtf.org/schemas/v1/Manager.v1_9_0.json

"ActiveSoftwareImage": {
...
    "description": "The link to the software inventory resource that
represents the active firmware image for this manager.",
    "longDescription": "This property shall contain a link to a resource
of type SoftwareInventory that represents the active firmware image for
this manager.",
    "readonly": false,
    "versionAdded": "v1_6_0"

PATCH support will come later.

Tested: Validator passes
Manager:
...
  "FirmwareVersion": "2.9.0-dev-515-g92efac612-dirty",
...
  "Links": {
    "ActiveSoftwareImage": {
      "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/82d3ec86"
    },
    "ManagerForChassis": [
      {
        "@odata.id": "/redfish/v1/Chassis/chassis"
      }
    ],
...
System:
  "BiosVersion": "IBM-witherspoon-OP9-v2.3-rc2-3.28",

Bios:
    "ActiveSoftwareImage": {
      "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/9f75c5ad"
    }
  },

Change-Id: Ia3583b4cb513bf36942a9dcbc4588615275bb2ad
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/redfish-core/include/utils/fw_utils.hpp b/redfish-core/include/utils/fw_utils.hpp
index 9aa5674..95d684f 100644
--- a/redfish-core/include/utils/fw_utils.hpp
+++ b/redfish-core/include/utils/fw_utils.hpp
@@ -2,6 +2,7 @@
 #include <async_resp.hpp>
 
 #include <string>
+#include <variant>
 
 namespace redfish
 {
@@ -20,19 +21,24 @@
  *
  * @param[i,o] aResp             Async response object
  * @param[i]   fwVersionPurpose  Indicates what target to look for
- * @param[i]   jsonIdxStr        Index in aResp->res.jsonValue to write fw ver
+ * @param[i]   activeVersionPropName  Index in aResp->res.jsonValue to write
+ * the running firmware version to
+ * @param[i]   populateLinkToActiveImage  Populate aResp->res "Links"
+ * "ActiveSoftwareImage" with a link to the running firmware image
  *
  * @return void
  */
 void getActiveFwVersion(std::shared_ptr<AsyncResp> aResp,
                         const std::string& fwVersionPurpose,
-                        const std::string& jsonIdxStr)
+                        const std::string& activeVersionPropName,
+                        const bool populateLinkToActiveImage)
 {
     // Get active FW images
     crow::connections::systemBus->async_method_call(
-        [aResp, fwVersionPurpose,
-         jsonIdxStr](const boost::system::error_code ec,
-                     const std::variant<std::vector<std::string>>& resp) {
+        [aResp, fwVersionPurpose, activeVersionPropName,
+         populateLinkToActiveImage](
+            const boost::system::error_code ec,
+            const std::variant<std::vector<std::string>>& resp) {
             if (ec)
             {
                 BMCWEB_LOG_ERROR << "error_code = " << ec;
@@ -72,7 +78,8 @@
 
                 // Now find service that hosts it
                 crow::connections::systemBus->async_method_call(
-                    [aResp, fw, swId, fwVersionPurpose, jsonIdxStr](
+                    [aResp, fw, swId, fwVersionPurpose, activeVersionPropName,
+                     populateLinkToActiveImage](
                         const boost::system::error_code ec,
                         const std::vector<std::pair<
                             std::string, std::vector<std::string>>>& objInfo) {
@@ -107,10 +114,13 @@
 
                         // Now grab its version info
                         crow::connections::systemBus->async_method_call(
-                            [aResp, swId, fwVersionPurpose, jsonIdxStr](
+                            [aResp, swId, fwVersionPurpose,
+                             activeVersionPropName, populateLinkToActiveImage](
                                 const boost::system::error_code ec,
                                 const boost::container::flat_map<
-                                    std::string, VariantType>& propertiesList) {
+                                    std::string,
+                                    std::variant<bool, std::string, uint64_t,
+                                                 uint32_t>>& propertiesList) {
                                 if (ec)
                                 {
                                     BMCWEB_LOG_ERROR << "error_code = " << ec;
@@ -126,8 +136,10 @@
                                 // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
 
                                 boost::container::flat_map<
-                                    std::string, VariantType>::const_iterator
-                                    it = propertiesList.find("Purpose");
+                                    std::string,
+                                    std::variant<bool, std::string, uint64_t,
+                                                 uint32_t>>::const_iterator it =
+                                    propertiesList.find("Purpose");
                                 if (it == propertiesList.end())
                                 {
                                     BMCWEB_LOG_DEBUG
@@ -150,24 +162,45 @@
                                     // Not purpose we're looking for
                                     return;
                                 }
-                                it = propertiesList.find("Version");
-                                if (it == propertiesList.end())
+                                if (populateLinkToActiveImage)
                                 {
-                                    BMCWEB_LOG_DEBUG
-                                        << "Can't find property \"Version\"!";
-                                    messages::internalError(aResp->res);
-                                    return;
+                                    // Firmware images are at
+                                    // /redfish/v1/UpdateService/FirmwareInventory/<Id>
+                                    // e.g. .../FirmwareInventory/82d3ec86
+                                    // Create the link to the running one
+                                    aResp->res
+                                        .jsonValue["Links"]
+                                                  ["ActiveSoftwareImage"] = {
+                                        {"@odata.id",
+                                         "/redfish/v1/UpdateService/"
+                                         "FirmwareInventory/" +
+                                             swId}};
                                 }
-                                const std::string* version =
-                                    std::get_if<std::string>(&it->second);
-                                if (version == nullptr)
+                                if (!activeVersionPropName.empty())
                                 {
-                                    BMCWEB_LOG_DEBUG
-                                        << "Error getting fw version";
-                                    messages::internalError(aResp->res);
-                                    return;
+                                    it = propertiesList.find("Version");
+                                    if (it == propertiesList.end())
+                                    {
+                                        BMCWEB_LOG_DEBUG
+                                            << "Can't find property "
+                                               "\"Version\"!";
+                                        messages::internalError(aResp->res);
+                                        return;
+                                    }
+                                    const std::string* version =
+                                        std::get_if<std::string>(&it->second);
+                                    if (version == nullptr)
+                                    {
+                                        BMCWEB_LOG_DEBUG
+                                            << "Error getting fw version";
+                                        messages::internalError(aResp->res);
+                                        return;
+                                    }
+
+                                    aResp->res
+                                        .jsonValue[activeVersionPropName] =
+                                        *version;
                                 }
-                                aResp->res.jsonValue[jsonIdxStr] = *version;
                             },
                             objInfo[0].first, fw,
                             "org.freedesktop.DBus.Properties", "GetAll",
@@ -268,16 +301,19 @@
     crow::connections::systemBus->async_method_call(
         [asyncResp,
          swId](const boost::system::error_code error_code,
-               const boost::container::flat_map<std::string, VariantType>&
-                   propertiesList) {
+               const boost::container::flat_map<
+                   std::string, std::variant<bool, std::string, uint64_t,
+                                             uint32_t>>& propertiesList) {
             if (error_code)
             {
                 // not all fwtypes are updateable, this is ok
                 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
                 return;
             }
-            boost::container::flat_map<std::string, VariantType>::const_iterator
-                it = propertiesList.find("Activation");
+            boost::container::flat_map<
+                std::string, std::variant<bool, std::string, uint64_t,
+                                          uint32_t>>::const_iterator it =
+                propertiesList.find("Activation");
             if (it == propertiesList.end())
             {
                 BMCWEB_LOG_DEBUG << "Can't find property \"Activation\"!";
diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
index 9e0a294..0a0effa 100644
--- a/redfish-core/lib/bios.hpp
+++ b/redfish-core/lib/bios.hpp
@@ -2,6 +2,7 @@
 
 #include "node.hpp"
 
+#include <utils/fw_utils.hpp>
 namespace redfish
 {
 /**
@@ -30,6 +31,9 @@
         asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = {
             {"target",
              "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}};
+
+        // Get the ActiveSoftwareImage
+        fw_util::getActiveFwVersion(asyncResp, fw_util::biosPurpose, "", true);
     }
 };
 /**
@@ -70,4 +74,4 @@
             "xyz.openbmc_project.Common.FactoryReset", "Reset");
     }
 };
-} // namespace redfish
\ No newline at end of file
+} // namespace redfish
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index bb7165e..7832e81 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -1754,7 +1754,7 @@
         health->populate();
 
         fw_util::getActiveFwVersion(asyncResp, fw_util::bmcPurpose,
-                                    "FirmwareVersion");
+                                    "FirmwareVersion", true);
 
         getLastResetTime(asyncResp);
 
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 50e2b93..2baeaa7 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -534,7 +534,7 @@
                                     // Grab the bios version
                                     fw_util::getActiveFwVersion(
                                         aResp, fw_util::biosPurpose,
-                                        "BiosVersion");
+                                        "BiosVersion", false);
                                 },
                                 connection.first, path,
                                 "org.freedesktop.DBus.Properties", "GetAll",