Redfish: ApplyTime property patch support

This change is to set the ApplyTime property using the UpdateServce
redfish schema before initiating the BMC image upload and activation.

Verified sequence flow:
1. The user sets the desired ApplyTime value (OnReset/Immediate) using
   the PATCH request
2. Execute "POST -T ./obmc-phosphor-image-witherspoon-20190522045427.ubi.mtd.tar
   https://${bmc}/redfish/v1/UpdateService"
3. During the end of activation, if the ApplyTime value is Immediate,
   force-reboot.service gets called  which reboots the BMC. If the ApplyTime
   value is OnReset, no force reboot will be triggered and the new BMC image
   will be functional when the user decideds to reboot the BMC manually.

Tested:
PATCH -d '{ "ApplyTime":"OnReset"}' https://${bmc}/redfish/v1/UpdateServce
{
  "@Message.ExtendedInfo": [
    {
      "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
      "Message": "Successfully Completed Request",
      "MessageArgs": [],
      "MessageId": "Base.1.4.0.Success",
      "Resolution": "None",
      "Severity": "OK"
    }
  ]
}

PATCH -d '{ "ApplyTime":"OnRset"}' https://${bmc}/redfish/v1/UpdateServie
{
  "ApplyTime@Message.ExtendedInfo": [
    {
      "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
      "Message": "The value OnRset for the property ApplyTime is not in the list of acceptable values.",
      "MessageArgs": [
        "OnRset",
        "ApplyTime"
      ],
      "MessageId": "Base.1.4.0.PropertyValueNotInList",
      "Resolution": "Choose a value from the enumeration list that the implementation can support and resubmit the request if the operation failed.",
      "Severity": "Warning"
    }
  ]
}

Signed-off-by: Jayashankar Padath <jayashankar.padath@in.ibm.com>
Change-Id: If79934f7db450c2ad3bea60307419b17981e4dfe
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 6b1b38c..06c1965 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -202,6 +202,59 @@
         res.end();
     }
 
+    void doPatch(crow::Response &res, const crow::Request &req,
+                 const std::vector<std::string> &params) override
+    {
+        BMCWEB_LOG_DEBUG << "doPatch...";
+
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+        std::string applyTime;
+
+        if (!json_util::readJson(req, res, "ApplyTime", applyTime))
+        {
+            return;
+        }
+
+        if ((applyTime == "Immediate") || (applyTime == "OnReset"))
+        {
+            std::string applyTimeNewVal;
+            if (applyTime == "Immediate")
+            {
+                applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime."
+                                  "RequestedApplyTimes.Immediate";
+            }
+            else
+            {
+                applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime."
+                                  "RequestedApplyTimes.OnReset";
+            }
+
+            // Set the requested image apply time value
+            crow::connections::systemBus->async_method_call(
+                [asyncResp](const boost::system::error_code ec) {
+                    if (ec)
+                    {
+                        BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+                        messages::internalError(asyncResp->res);
+                        return;
+                    }
+                    messages::success(asyncResp->res);
+                },
+                "xyz.openbmc_project.Settings",
+                "/xyz/openbmc_project/software/apply_time",
+                "org.freedesktop.DBus.Properties", "Set",
+                "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
+                std::variant<std::string>{applyTimeNewVal});
+        }
+        else
+        {
+            BMCWEB_LOG_INFO << "ApplyTime value is not in the list of "
+                               "acceptable values";
+            messages::propertyValueNotInList(asyncResp->res, applyTime,
+                                             "ApplyTime");
+        }
+    }
+
     void doPost(crow::Response &res, const crow::Request &req,
                 const std::vector<std::string> &params) override
     {