Support for configurable host reboot count

ComputerSystem.v1.11 introduced a new property, AutomaticRetryAttempts,
which allows for the amount of automatic retry attempts on host boot
failures to be configured through Redfish. This commit adds support
for this new property.
The added function "setAutomaticRetryAttempts()" allows users to set the
"RetryAttempts" property externally through bmcweb. This property is
documented in D-Bus and has a default value of 3. All implementations
of the interface have this property implemented. The new code preserves
backward compatibility and does not break any existing user-facing
behavior.

Tested:
   - Ensured that the new "AutomaticRetryAttempts" property could be
     retrieved through bmcweb. Verified that it was accurately
     representing its corresponding DBus property, "RetryAttempts".

   - Sent curl commands to patch the "AutomaticRetryAttempts" property
     which also updates the "AttemptsLeft" DBus property represented as
     "RemainingAutomaticRetryAttempts" as expected.

   - Verified that changes made to "RetryAttempts" through DBus were
     accurately represented in successive "Gets" from bmcweb.

   - Passed Redfish Validator

curl -k -H "X-AUTH" -X GET https://${BMC_IP}/redfish/v1/Systems/system/

"Boot": {
    "AutomaticRetryAttempts": 3,
    "AutomaticRetryConfig": "RetryAttempts",
    "AutomaticRetryConfig@Redfish.AllowableValues": [
      "Disabled",
      "RetryAttempts"
    ],
    "RemainingAutomaticRetryAttempts": 3,
    "StopBootOnFault": "Never",
    "TrustedModuleRequiredToBoot": "Disabled"
  },

curl -k -X PATCH  https://${BMC_IP}/redfish/v1/Systems/system/ -d '{"Boot":
{"AutomaticRetryAttempts":4}}'

"Boot": {
    "AutomaticRetryAttempts": 4,
    "AutomaticRetryConfig": "RetryAttempts",
    "AutomaticRetryConfig@Redfish.AllowableValues": [
      "Disabled",
      "RetryAttempts"
    ],
    "RemainingAutomaticRetryAttempts": 4,
    "StopBootOnFault": "Never",
    "TrustedModuleRequiredToBoot": "Disabled"
  },

Signed-off-by: Corey Hardesty <corey.hardesty@icloud.com>
Change-Id: I034782847a2318e2604bdd0cf33cdf705d224acb
Signed-off-by: Lakshmi Yadlapati <lakshmiy@us.ibm.com>
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 029ce58..c9d31d1 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -1150,13 +1150,74 @@
 }
 
 /**
+ * @brief Retrieves the number of automatic boot Retry attempts allowed/left.
+ *
+ * The total number of automatic reboot retries allowed "RetryAttempts" and its
+ * corresponding property "AttemptsLeft" that keeps track of the amount of
+ * automatic retry attempts left are hosted in phosphor-state-manager through
+ * dbus.
+ *
+ * @param[in] aResp     Shared pointer for generating response message.
+ *
+ * @return None.
+ */
+inline void
+    getAutomaticRebootAttempts(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
+{
+    BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
+
+    sdbusplus::asio::getAllProperties(
+        *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
+        "/xyz/openbmc_project/state/host0",
+        "xyz.openbmc_project.Control.Boot.RebootAttempts",
+        [aResp{aResp}](const boost::system::error_code& ec,
+                       const dbus::utility::DBusPropertiesMap& propertiesList) {
+        if (ec)
+        {
+            if (ec.value() != EBADR)
+            {
+                BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+                messages::internalError(aResp->res);
+            }
+            return;
+        }
+
+        const uint32_t* attemptsLeft = nullptr;
+        const uint32_t* retryAttempts = nullptr;
+
+        const bool success = sdbusplus::unpackPropertiesNoThrow(
+            dbus_utils::UnpackErrorPrinter(), propertiesList, "AttemptsLeft",
+            attemptsLeft, "RetryAttempts", retryAttempts);
+
+        if (!success)
+        {
+            messages::internalError(aResp->res);
+            return;
+        }
+
+        if (attemptsLeft != nullptr)
+        {
+            aResp->res.jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
+                *attemptsLeft;
+        }
+
+        if (retryAttempts != nullptr)
+        {
+            aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] =
+                *retryAttempts;
+        }
+        });
+}
+
+/**
  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
  *
  * @param[in] aResp     Shared pointer for generating response message.
  *
  * @return None.
  */
-inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
+inline void
+    getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
 {
     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
 
@@ -1167,7 +1228,11 @@
         [aResp](const boost::system::error_code& ec, bool autoRebootEnabled) {
         if (ec)
         {
-            BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
+            if (ec.value() != EBADR)
+            {
+                BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+                messages::internalError(aResp->res);
+            }
             return;
         }
 
@@ -1176,37 +1241,12 @@
         {
             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
                 "RetryAttempts";
-            // If AutomaticRetry (AutoReboot) is enabled see how many
-            // attempts are left
-            sdbusplus::asio::getProperty<uint32_t>(
-                *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
-                "/xyz/openbmc_project/state/host0",
-                "xyz.openbmc_project.Control.Boot.RebootAttempts",
-                "AttemptsLeft",
-                [aResp](const boost::system::error_code& ec2,
-                        const uint32_t autoRebootAttemptsLeft) {
-                if (ec2)
-                {
-                    BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
-                    return;
-                }
-
-                BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
-                                 << autoRebootAttemptsLeft;
-
-                aResp->res
-                    .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
-                    autoRebootAttemptsLeft;
-                });
         }
         else
         {
             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled";
         }
-
-        // Not on D-Bus. Hardcoded here:
-        // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
-        aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
+        getAutomaticRebootAttempts(aResp);
 
         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
         // and RetryAttempts. OpenBMC only supports Disabled and
@@ -1218,6 +1258,36 @@
 }
 
 /**
+ * @brief Sets RetryAttempts
+ *
+ * @param[in] aResp   Shared pointer for generating response message.
+ * @param[in] retryAttempts  "AutomaticRetryAttempts" from request.
+ *
+ *@return None.
+ */
+
+inline void
+    setAutomaticRetryAttempts(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
+                              const uint32_t retryAttempts)
+{
+    BMCWEB_LOG_DEBUG << "Set Automatic Retry Attempts.";
+    crow::connections::systemBus->async_method_call(
+        [aResp](const boost::system::error_code& ec) {
+        if (ec)
+        {
+            BMCWEB_LOG_ERROR
+                << "DBUS response error: Set setAutomaticRetryAttempts" << ec;
+            messages::internalError(aResp->res);
+            return;
+        }
+        },
+        "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
+        "org.freedesktop.DBus.Properties", "Set",
+        "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts",
+        std::variant<uint32_t>(retryAttempts));
+}
+
+/**
  * @brief Retrieves power restore policy over DBUS.
  *
  * @param[in] aResp     Shared pointer for generating response message.
@@ -3068,7 +3138,7 @@
         getPCIeDeviceList(asyncResp, "PCIeDevices");
         getHostWatchdogTimer(asyncResp);
         getPowerRestorePolicy(asyncResp);
-        getAutomaticRetry(asyncResp);
+        getAutomaticRetryPolicy(asyncResp);
         getLastResetTime(asyncResp);
 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
         getProvisioningStatus(asyncResp);
@@ -3110,6 +3180,7 @@
         std::optional<std::string> bootType;
         std::optional<std::string> bootEnable;
         std::optional<std::string> bootAutomaticRetry;
+        std::optional<uint32_t> bootAutomaticRetryAttempts;
         std::optional<bool> bootTrustedModuleRequired;
         std::optional<bool> ipsEnable;
         std::optional<uint8_t> ipsEnterUtil;
@@ -3131,6 +3202,7 @@
                         "Boot/BootSourceOverrideMode", bootType,
                         "Boot/BootSourceOverrideEnabled", bootEnable,
                         "Boot/AutomaticRetryConfig", bootAutomaticRetry,
+                        "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts,
                         "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
                         "IdlePowerSaver/Enabled", ipsEnable,
                         "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
@@ -3163,6 +3235,12 @@
             setAutomaticRetry(asyncResp, *bootAutomaticRetry);
         }
 
+        if (bootAutomaticRetryAttempts)
+        {
+            setAutomaticRetryAttempts(asyncResp,
+                                      bootAutomaticRetryAttempts.value());
+        }
+
         if (bootTrustedModuleRequired)
         {
             setTrustedModuleRequiredToBoot(asyncResp,