FW Update: Task: Update messages

This adds reporting of percent updated and changes
"staged" to paused to indicate some further action
must happen to change state to Completed.

Tested: validator passed

 "Messages": [
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has started.",
        "MessageArgs": [
            "2"
        ],
        "MessageId": "TaskEvent.1.0.1.TaskStarted",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 5 percent complete.",
        "MessageArgs": [
            "2",
            5
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 10 percent complete.",
        "MessageArgs": [
            "2",
            10
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 15 percent complete.",
        "MessageArgs": [
            "2",
            15
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 20 percent complete.",
        "MessageArgs": [
            "2",
            20
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 25 percent complete.",
        "MessageArgs": [
            "2",
            25
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 30 percent complete.",
        "MessageArgs": [
            "2",
            30
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 35 percent complete.",
        "MessageArgs": [
            "2",
            35
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 40 percent complete.",
        "MessageArgs": [
            "2",
            40
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 45 percent complete.",
        "MessageArgs": [
            "2",
            45
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 50 percent complete.",
        "MessageArgs": [
            "2",
            50
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 55 percent complete.",
        "MessageArgs": [
            "2",
            55
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 60 percent complete.",
        "MessageArgs": [
            "2",
            60
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 65 percent complete.",
        "MessageArgs": [
            "2",
            65
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 70 percent complete.",
        "MessageArgs": [
            "2",
            70
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 75 percent complete.",
        "MessageArgs": [
            "2",
            75
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 80 percent complete.",
        "MessageArgs": [
            "2",
            80
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 85 percent complete.",
        "MessageArgs": [
            "2",
            85
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 90 percent complete.",
        "MessageArgs": [
            "2",
            90
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 95 percent complete.",
        "MessageArgs": [
            "2",
            95
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has changed to progress 100 percent complete.",
        "MessageArgs": [
            "2",
            100
        ],
        "MessageId": "TaskEvent.1.0.1.TaskProgressChanged",
        "Resolution": "None.",
        "Severity": "OK"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has been paused.",
        "MessageArgs": [
            "2"
        ],
        "MessageId": "TaskEvent.1.0.1.TaskPaused",
        "Resolution": "None.",
        "Severity": "Warning"
    },
    {
        "@odata.type": "#Message.v1_0_0.Message",
        "Message": "The task with id 2 has Completed.",
        "MessageArgs": [
            "2"
        ],
        "MessageId": "TaskEvent.1.0.1.TaskCompletedOK",
        "Resolution": "None.",
        "Severity": "OK"
    }
],

Change-Id: I32103e53486d459fe945a8b451d2092232c12e83
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index cbae67b..a746239 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -168,28 +168,8 @@
             std::chrono::system_clock::now());
     }
 
-    void startTimer(const std::chrono::seconds &timeout)
+    void extendTimer(const std::chrono::seconds &timeout)
     {
-        match = std::make_unique<sdbusplus::bus::match::match>(
-            static_cast<sdbusplus::bus::bus &>(*crow::connections::systemBus),
-            matchStr,
-            [self = shared_from_this()](sdbusplus::message::message &message) {
-                boost::system::error_code ec;
-
-                // callback to return True if callback is done, callback needs
-                // to update status itself if needed
-                if (self->callback(ec, message, self) == task::completed)
-                {
-                    self->timer.cancel();
-                    self->finishTask();
-
-                    // reset the match after the callback was successful
-                    boost::asio::post(
-                        crow::connections::systemBus->get_io_context(),
-                        [self] { self->match.reset(); });
-                    return;
-                }
-            });
         timer.expires_after(timeout);
         timer.async_wait(
             [self = shared_from_this()](boost::system::error_code ec) {
@@ -211,6 +191,36 @@
                     messages::taskAborted(std::to_string(self->index)));
                 self->callback(ec, msg, self);
             });
+    }
+
+    void startTimer(const std::chrono::seconds &timeout)
+    {
+        if (match)
+        {
+            return;
+        }
+        match = std::make_unique<sdbusplus::bus::match::match>(
+            static_cast<sdbusplus::bus::bus &>(*crow::connections::systemBus),
+            matchStr,
+            [self = shared_from_this()](sdbusplus::message::message &message) {
+                boost::system::error_code ec;
+
+                // callback to return True if callback is done, callback needs
+                // to update status itself if needed
+                if (self->callback(ec, message, self) == task::completed)
+                {
+                    self->timer.cancel();
+                    self->finishTask();
+
+                    // reset the match after the callback was successful
+                    boost::asio::post(
+                        crow::connections::systemBus->get_io_context(),
+                        [self] { self->match.reset(); });
+                    return;
+                }
+            });
+
+        extendTimer(timeout);
         messages.emplace_back(messages::taskStarted(std::to_string(index)));
     }
 
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 60d6673..9dacbcd 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -131,51 +131,99 @@
 
                                     std::string iface;
                                     boost::container::flat_map<
-                                        std::string, std::variant<std::string>>
+                                        std::string,
+                                        std::variant<std::string, uint8_t>>
                                         values;
-                                    msg.read(iface, values);
-                                    auto findActivation =
-                                        values.find("Activation");
-                                    if (findActivation == values.end())
-                                    {
-                                        return !task::completed;
-                                    }
-                                    std::string *state =
-                                        std::get_if<std::string>(
-                                            &(findActivation->second));
-
-                                    if (state == nullptr)
-                                    {
-                                        taskData->messages.emplace_back(
-                                            messages::internalError());
-                                        return task::completed;
-                                    }
 
                                     std::string index =
                                         std::to_string(taskData->index);
+                                    msg.read(iface, values);
 
-                                    if (boost::ends_with(*state, "Invalid") ||
-                                        boost::ends_with(*state, "Failed"))
+                                    if (iface == "xyz.openbmc_project.Software."
+                                                 "Activation")
                                     {
-                                        taskData->state = "Exception";
-                                        taskData->status = "Warning";
-                                        taskData->messages.emplace_back(
-                                            messages::taskAborted(index));
-                                        return task::completed;
+                                        auto findActivation =
+                                            values.find("Activation");
+                                        if (findActivation == values.end())
+                                        {
+                                            return !task::completed;
+                                        }
+                                        std::string *state =
+                                            std::get_if<std::string>(
+                                                &(findActivation->second));
+
+                                        if (state == nullptr)
+                                        {
+                                            taskData->messages.emplace_back(
+                                                messages::internalError());
+                                            return task::completed;
+                                        }
+
+                                        if (boost::ends_with(*state,
+                                                             "Invalid") ||
+                                            boost::ends_with(*state, "Failed"))
+                                        {
+                                            taskData->state = "Exception";
+                                            taskData->status = "Warning";
+                                            taskData->messages.emplace_back(
+                                                messages::taskAborted(index));
+                                            return task::completed;
+                                        }
+
+                                        if (boost::ends_with(*state, "Staged"))
+                                        {
+                                            taskData->state = "Stopping";
+                                            taskData->messages.emplace_back(
+                                                messages::taskPaused(index));
+
+                                            // its staged, set a long timer to
+                                            // allow them time to complete the
+                                            // update (probably cycle the
+                                            // system) if this expires then
+                                            // task will be cancelled
+                                            taskData->extendTimer(
+                                                std::chrono::hours(5));
+                                            return !task::completed;
+                                        }
+
+                                        if (boost::ends_with(*state, "Active"))
+                                        {
+                                            taskData->messages.emplace_back(
+                                                messages::taskCompletedOK(
+                                                    index));
+                                            taskData->state = "Completed";
+                                            return task::completed;
+                                        }
                                     }
-
-                                    if (boost::ends_with(*state, "Staged"))
+                                    else if (iface ==
+                                             "xyz.openbmc_project.Software."
+                                             "ActivationProgress")
                                     {
-                                        taskData->state = "Pending";
-                                        return !task::completed;
-                                    }
+                                        auto findProgress =
+                                            values.find("Progress");
+                                        if (findProgress == values.end())
+                                        {
+                                            return !task::completed;
+                                        }
+                                        uint8_t *progress =
+                                            std::get_if<uint8_t>(
+                                                &(findProgress->second));
 
-                                    if (boost::ends_with(*state, "Active"))
-                                    {
+                                        if (progress == nullptr)
+                                        {
+                                            taskData->messages.emplace_back(
+                                                messages::internalError());
+                                            return task::completed;
+                                        }
                                         taskData->messages.emplace_back(
-                                            messages::taskCompletedOK(index));
-                                        taskData->state = "Completed";
-                                        return task::completed;
+                                            messages::taskProgressChanged(
+                                                index, static_cast<size_t>(
+                                                           *progress)));
+
+                                        // if we're getting status updates it's
+                                        // still alive, update timer
+                                        taskData->extendTimer(
+                                            std::chrono::minutes(5));
                                     }
 
                                     // as firmware update often results in a
@@ -186,8 +234,7 @@
                                 },
                                 "type='signal',interface='org.freedesktop.DBus."
                                 "Properties',"
-                                "member='PropertiesChanged',arg0='xyz.openbmc_"
-                                "project.Software.Activation',path='" +
+                                "member='PropertiesChanged',path='" +
                                     objPath.str + "'");
                         task->startTimer(std::chrono::minutes(5));
                         task->populateResp(asyncResp->res);