Add Crashdump.Telemetry interface and trigger

Tested:
- Sent post requests Crashdump.OnDemand & Crashdump.Telemetry
and correct trigger is received in crashdump application.
- Redfish validator is run successfully.

Signed-off-by: Kenny K. Ku <kenny.k.ku@intel.com>
Change-Id: Ie0f49d3230aeb4450e11dfa2d46e309946763a6a
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index bdff035..303519b 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -131,6 +131,7 @@
         nodes.emplace_back(std::make_unique<CrashdumpFile>(app));
         nodes.emplace_back(std::make_unique<CrashdumpClear>(app));
         nodes.emplace_back(std::make_unique<OnDemandCrashdump>(app));
+        nodes.emplace_back(std::make_unique<TelemetryCrashdump>(app));
 #ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
         nodes.emplace_back(std::make_unique<SendRawPECI>(app));
 #endif // BMCWEB_ENABLE_REDFISH_RAW_PECI
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 753334e..52a51a6 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -39,7 +39,6 @@
 
 constexpr char const* crashdumpObject = "com.intel.crashdump";
 constexpr char const* crashdumpPath = "/com/intel/crashdump";
-constexpr char const* crashdumpOnDemandPath = "/com/intel/crashdump/OnDemand";
 constexpr char const* crashdumpInterface = "com.intel.crashdump";
 constexpr char const* deleteAllInterface =
     "xyz.openbmc_project.Collection.DeleteAll";
@@ -47,6 +46,8 @@
     "com.intel.crashdump.OnDemand";
 constexpr char const* crashdumpRawPECIInterface =
     "com.intel.crashdump.SendRawPeci";
+constexpr char const* crashdumpTelemetryInterface =
+    "com.intel.crashdump.Telemetry";
 
 namespace message_registries
 {
@@ -1980,7 +1981,10 @@
             {"Oem",
              {{"#Crashdump.OnDemand",
                {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
-                           "Actions/Oem/Crashdump.OnDemand"}}}}}};
+                           "Actions/Oem/Crashdump.OnDemand"}}},
+              {"#Crashdump.Telemetry",
+               {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
+                           "Actions/Oem/Crashdump.Telemetry"}}}}}};
 
 #ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
         asyncResp->res.jsonValue["Actions"]["Oem"].push_back(
@@ -2379,6 +2383,78 @@
     }
 };
 
+class TelemetryCrashdump : public Node
+{
+  public:
+    TelemetryCrashdump(CrowApp& app) :
+        Node(app,
+             "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/Oem/"
+             "Crashdump.Telemetry/")
+    {
+        // Note: Deviated from redfish privilege registry for GET & HEAD
+        // method for security reasons.
+        entityPrivileges = {
+            {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+            {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+    }
+
+  private:
+    void doPost(crow::Response& res, const crow::Request& req,
+                const std::vector<std::string>& params) override
+    {
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+        auto generateTelemetryLogCallback = [asyncResp, req](
+                                                const boost::system::error_code
+                                                    ec,
+                                                const std::string& resp) {
+            if (ec)
+            {
+                if (ec.value() == boost::system::errc::operation_not_supported)
+                {
+                    messages::resourceInStandby(asyncResp->res);
+                }
+                else if (ec.value() ==
+                         boost::system::errc::device_or_resource_busy)
+                {
+                    messages::serviceTemporarilyUnavailable(asyncResp->res,
+                                                            "60");
+                }
+                else
+                {
+                    messages::internalError(asyncResp->res);
+                }
+                return;
+            }
+            std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
+                [](boost::system::error_code err, sdbusplus::message::message&,
+                   const std::shared_ptr<task::TaskData>& taskData) {
+                    if (!err)
+                    {
+                        taskData->messages.emplace_back(
+                            messages::taskCompletedOK(
+                                std::to_string(taskData->index)));
+                        taskData->state = "Completed";
+                    }
+                    return task::completed;
+                },
+                "type='signal',interface='org.freedesktop.DBus.Properties',"
+                "member='PropertiesChanged',arg0namespace='com.intel."
+                "crashdump'");
+            task->startTimer(std::chrono::minutes(5));
+            task->populateResp(asyncResp->res);
+            task->payload.emplace(req);
+        };
+        crow::connections::systemBus->async_method_call(
+            std::move(generateTelemetryLogCallback), crashdumpObject,
+            crashdumpPath, crashdumpTelemetryInterface, "GenerateTelemetryLog");
+    }
+};
+
 class SendRawPECI : public Node
 {
   public: