Move to Redfish Action specific setProperty call

This commit will migrate all the setProperty calls initiated by a
redfish"Action" to "setDbusProperty" method in Redfish namespace that
handles all DBuserrors in a consistent manner.

This method will determine if a setProperty is called during redfish
"Action" or just setting of a dbus property and internally call
appropriate methods that handles different set of errors.

All the Redfish action specific errors are defined in error_messages.hpp
file.
This specific change moves setProperty call in hypervisor_system.hpp and
covers  errors in the mentioned file only.

Tested-By:
<Yet to test this usecase>

Change-Id: I3da48fbeabcdcf088c4481021232f08a44797c86
Signed-off-by: Asmitha Karunanithi <asmitk01@in.ibm.com>
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
index 7adae19..91edc3c 100644
--- a/redfish-core/include/error_messages.hpp
+++ b/redfish-core/include/error_messages.hpp
@@ -851,6 +851,21 @@
                                    std::string_view arg3);
 
 /**
+ * @brief Formats ActionParameterValueError message into JSON
+ * Message body: "Indicates that a parameter was given an invalid value."
+ *  The value for the parameter %1 in the action %2 is invalid.
+ *
+ * @param[in] arg1 Parameter of message that will replace %1 in its body.
+ * @param[in] arg2 Parameter of message that will replace %2 in its body.
+ *
+ * @returns Message ActionParameterValueError formatted to JSON */
+nlohmann::json actionParameterValueError(const nlohmann::json& arg1,
+                                         std::string_view arg2);
+
+void actionParameterValueError(crow::Response& res, const nlohmann::json& arg1,
+                               std::string_view arg2);
+
+/**
  * @brief Formats SessionLimitExceeded message into JSON
  * Message body: "The session establishment failed due to the number of
  * simultaneous sessions exceeding the limit of the implementation."
diff --git a/redfish-core/include/utils/dbus_utils.hpp b/redfish-core/include/utils/dbus_utils.hpp
index cd7e0e2..8057169 100644
--- a/redfish-core/include/utils/dbus_utils.hpp
+++ b/redfish-core/include/utils/dbus_utils.hpp
@@ -39,7 +39,13 @@
                       const nlohmann::json& propertyValue,
                       const boost::system::error_code& ec,
                       const sdbusplus::message_t& msg);
-}
+
+void afterSetPropertyAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                            const std::string& redfishActionName,
+                            const std::string& redfishActionParameterName,
+                            const boost::system::error_code& ec,
+                            const sdbusplus::message_t& msg);
+} // namespace details
 
 template <typename PropertyType>
 void setDbusProperty(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
@@ -64,4 +70,32 @@
     });
 }
 
+template <typename DbusPropertyType>
+void setDbusPropertyAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                           std::string_view processName,
+                           const sdbusplus::message::object_path& path,
+                           std::string_view interface,
+                           std::string_view dbusProperty,
+                           std::string_view redfishActionParameterName,
+                           std::string_view redfishActionName,
+                           const DbusPropertyType& prop)
+{
+    std::string processNameStr(processName);
+    std::string interfaceStr(interface);
+    std::string dbusPropertyStr(dbusProperty);
+
+    sdbusplus::asio::setProperty(
+        *crow::connections::systemBus, processNameStr, path.str, interfaceStr,
+        dbusPropertyStr, prop,
+        [asyncResp,
+         redfishActionParameterName = std::string{redfishActionParameterName},
+         jsonProp = nlohmann::json(prop),
+         redfishActionNameStr = std::string{redfishActionName}](
+            const boost::system::error_code& ec,
+            const sdbusplus::message_t& msg) {
+        details::afterSetPropertyAction(asyncResp, redfishActionNameStr,
+                                        redfishActionParameterName, ec, msg);
+    });
+}
+
 } // namespace redfish
diff --git a/redfish-core/lib/hypervisor_system.hpp b/redfish-core/lib/hypervisor_system.hpp
index 2b3714b..ad1fae8 100644
--- a/redfish-core/lib/hypervisor_system.hpp
+++ b/redfish-core/lib/hypervisor_system.hpp
@@ -915,32 +915,12 @@
 
     std::string command = "xyz.openbmc_project.State.Host.Transition.On";
 
-    sdbusplus::asio::setProperty(
-        *crow::connections::systemBus, "xyz.openbmc_project.State.Hypervisor",
-        "/xyz/openbmc_project/state/hypervisor0",
-        "xyz.openbmc_project.State.Host", "RequestedHostTransition", command,
-        [asyncResp, resetType](const boost::system::error_code& ec) {
-        if (ec)
-        {
-            BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
-            if (ec.value() == boost::asio::error::invalid_argument)
-            {
-                messages::actionParameterNotSupported(asyncResp->res,
-                                                      *resetType, "Reset");
-                return;
-            }
-
-            if (ec.value() == boost::asio::error::host_unreachable)
-            {
-                messages::resourceNotFound(asyncResp->res, "Actions", "Reset");
-                return;
-            }
-
-            messages::internalError(asyncResp->res);
-            return;
-        }
-        messages::success(asyncResp->res);
-    });
+    setDbusPropertyAction(asyncResp, "xyz.openbmc_project.State.Hypervisor",
+                          sdbusplus::message::object_path(
+                              "/xyz/openbmc_project/state/hypervisor0"),
+                          "xyz.openbmc_project.State.Host",
+                          "RequestedHostTransition", "ResetType",
+                          "ComputerSystem.Reset", command);
 }
 
 inline void requestRoutesHypervisorSystems(App& app)
diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
index 6c4282c..7b02515 100644
--- a/redfish-core/src/error_messages.cpp
+++ b/redfish-core/src/error_messages.cpp
@@ -1453,6 +1453,29 @@
 
 /**
  * @internal
+ * @brief Formats actionParameterValueError message into JSON
+ *
+ * See header file for more information
+ * @endinternal
+ */
+nlohmann::json actionParameterValueError(const nlohmann::json& arg1,
+                                         std::string_view arg2)
+{
+    std::string arg1Str = arg1.dump(2, ' ', true,
+                                    nlohmann::json::error_handler_t::replace);
+    return getLog(redfish::registries::base::Index::actionParameterValueError,
+                  std::to_array<std::string_view>({arg1Str, arg2}));
+}
+
+void actionParameterValueError(crow::Response& res, const nlohmann::json& arg1,
+                               std::string_view arg2)
+{
+    res.result(boost::beast::http::status::bad_request);
+    addMessageToErrorJson(res.jsonValue, actionParameterValueError(arg1, arg2));
+}
+
+/**
+ * @internal
  * @brief Formats SessionLimitExceeded message into JSON
  *
  * See header file for more information
diff --git a/redfish-core/src/utils/dbus_utils.cpp b/redfish-core/src/utils/dbus_utils.cpp
index 59ddb9d..bffe7a8 100644
--- a/redfish-core/src/utils/dbus_utils.cpp
+++ b/redfish-core/src/utils/dbus_utils.cpp
@@ -66,7 +66,54 @@
         messages::internalError(asyncResp->res);
         return;
     }
-    // Only set 204 if another erro hasn't already happened.
+    // Only set 204 if another error hasn't already happened.
+    if (asyncResp->res.result() == boost::beast::http::status::ok)
+    {
+        asyncResp->res.result(boost::beast::http::status::no_content);
+    }
+};
+
+void afterSetPropertyAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                            const std::string& redfishActionName,
+                            const std::string& redfishActionParameterName,
+                            const boost::system::error_code& ec,
+                            const sdbusplus::message_t& /*msg*/)
+{
+    if (ec)
+    {
+        if (ec.value() == boost::asio::error::invalid_argument)
+        {
+            BMCWEB_LOG_WARNING(
+                "Resource {} is patched with invalid argument during action {}",
+                redfishActionParameterName, redfishActionName);
+            if (redfishActionParameterName.empty())
+            {
+                messages::operationFailed(asyncResp->res);
+            }
+            else
+            {
+                messages::actionParameterValueError(asyncResp->res,
+                                                    redfishActionParameterName,
+                                                    redfishActionName);
+            }
+            return;
+        }
+        if (ec.value() == boost::asio::error::host_unreachable)
+        {
+            BMCWEB_LOG_WARNING(
+                "Resource {} is not found while performing action {}",
+                redfishActionParameterName, redfishActionName);
+            messages::resourceNotFound(asyncResp->res, "Actions",
+                                       redfishActionName);
+            return;
+        }
+
+        BMCWEB_LOG_ERROR("D-Bus error setting Redfish Property {} ec={}",
+                         redfishActionParameterName, ec);
+        messages::internalError(asyncResp->res);
+        return;
+    }
+    // Only set 204 if another error hasn't already happened.
     if (asyncResp->res.result() == boost::beast::http::status::ok)
     {
         asyncResp->res.result(boost::beast::http::status::no_content);