EventService : Send event for the Task Lifecycle

The commit implements the Push style events when a Task
goes through its life cycle.

Tested by: (Used https://github.com/DMTF/Redfish-Event-Listener)
    1. Create a subscription by passing "ResourceTypes" as ["Task"]
       POST -D headers.txt https://${bmc}/redfish/v1/EventService/Subscriptions
       -d '{"Destination" : "https://<host:port>, "ResourceTypes":["Task"], "Protocol":"Redfish"}'
    2. Run a command which starts the Task
    3. Verify if the task state changes are reported as events

Signed-off-by: Sunitha Harish <sunharis@in.ibm.com>
Change-Id: I4cea83f221e6f4f40cfbdc3da3e95cd920744316
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index f7f0ff9..5698bc9 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -188,10 +188,83 @@
                 self->status = "Warning";
                 self->messages.emplace_back(
                     messages::taskAborted(std::to_string(self->index)));
+                // Send event :TaskAborted
+                self->sendTaskEvent(self->state, self->index);
                 self->callback(ec, msg, self);
             });
     }
 
+    void sendTaskEvent(const std::string_view state, size_t index)
+    {
+        std::string origin =
+            "/redfish/v1/TaskService/Tasks/" + std::to_string(index);
+        std::string resType = "Task";
+        // TaskState enums which should send out an event are:
+        // "Starting" = taskResumed
+        // "Running" = taskStarted
+        // "Suspended" = taskPaused
+        // "Interrupted" = taskPaused
+        // "Pending" = taskPaused
+        // "Stopping" = taskAborted
+        // "Completed" = taskCompletedOK
+        // "Killed" = taskRemoved
+        // "Exception" = taskCompletedWarning
+        // "Cancelled" = taskCancelled
+        if (state == "Starting")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskResumed(std::to_string(index)), origin,
+                resType);
+        }
+        else if (state == "Running")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskStarted(std::to_string(index)), origin,
+                resType);
+        }
+        else if ((state == "Suspended") || (state == "Interrupted") ||
+                 (state == "Pending"))
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskPaused(std::to_string(index)), origin,
+                resType);
+        }
+        else if (state == "Stopping")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskAborted(std::to_string(index)), origin,
+                resType);
+        }
+        else if (state == "Completed")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskCompletedOK(std::to_string(index)),
+                origin, resType);
+        }
+        else if (state == "Killed")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskRemoved(std::to_string(index)), origin,
+                resType);
+        }
+        else if (state == "Exception")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskCompletedWarning(std::to_string(index)),
+                origin, resType);
+        }
+        else if (state == "Cancelled")
+        {
+            redfish::EventServiceManager::getInstance().sendEvent(
+                redfish::messages::taskCancelled(std::to_string(index)), origin,
+                resType);
+        }
+        else
+        {
+            BMCWEB_LOG_INFO << "sendTaskEvent: No events to send";
+        }
+    }
+
     void startTimer(const std::chrono::seconds& timeout)
     {
         if (match)
@@ -211,6 +284,9 @@
                     self->timer.cancel();
                     self->finishTask();
 
+                    // Send event
+                    self->sendTaskEvent(self->state, self->index);
+
                     // reset the match after the callback was successful
                     boost::asio::post(
                         crow::connections::systemBus->get_io_context(),
@@ -221,6 +297,8 @@
 
         extendTimer(timeout);
         messages.emplace_back(messages::taskStarted(std::to_string(index)));
+        // Send event : TaskStarted
+        sendTaskEvent(state, index);
     }
 
     std::function<bool(boost::system::error_code, sdbusplus::message::message&,
@@ -440,8 +518,7 @@
         asyncResp->res.jsonValue["DateTime"] = crow::utility::dateTimeNow();
         asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] = "Oldest";
 
-        // todo: if we enable events, change this to true
-        asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] = false;
+        asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] = true;
 
         auto health = std::make_shared<HealthPopulate>(asyncResp);
         health->populate();