Add Report interface to dbus

Added AddReport method to ReportManager to allow dbus user
to create new Report. Added Report object with Report and Delete
interfaces.

Tested:
 - Verified that telemetry service works in romulus
 - Added and removed report from ReportManager collection

Change-Id: Ib20cfda1f0e27ef20b60e66d52c3d11f31f61a96
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
diff --git a/src/report.cpp b/src/report.cpp
new file mode 100644
index 0000000..45639aa
--- /dev/null
+++ b/src/report.cpp
@@ -0,0 +1,54 @@
+#include "report.hpp"
+
+#include "report_manager.hpp"
+
+constexpr const char* reportIfaceName = "xyz.openbmc_project.Telemetry.Report";
+constexpr const char* reportPath = "/xyz/openbmc_project/Telemetry/Reports/";
+constexpr const char* deleteIfaceName = "xyz.openbmc_project.Object.Delete";
+
+Report::Report(boost::asio::io_context& ioc,
+               const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
+               const std::string& reportName, const std::string& reportingType,
+               const bool emitsReadingsSignal,
+               const bool logToMetricReportsCollection,
+               const std::chrono::milliseconds period,
+               const ReadingParameters& metricParams,
+               ReportManager& reportManager) :
+    name{reportName},
+    path{reportPath + name}, interval{period}, objServer(objServer)
+{
+    reportIface = objServer->add_unique_interface(
+        path, reportIfaceName,
+        [this, &reportingType, &emitsReadingsSignal,
+         &logToMetricReportsCollection, &metricParams](auto& dbusIface) {
+            dbusIface.register_property(
+                "Interval", static_cast<uint64_t>(interval.count()),
+                [this](const uint64_t newVal, uint64_t& actualVal) {
+                    std::chrono::milliseconds newValT(newVal);
+                    if (newValT < ReportManager::minInterval)
+                    {
+                        return false;
+                    }
+                    actualVal = newVal;
+                    interval = newValT;
+                    return true;
+                });
+            dbusIface.register_property("Persistency", bool{false});
+            dbusIface.register_property("Readings", Readings{});
+            dbusIface.register_property("ReportingType", reportingType);
+            dbusIface.register_property("ReadingParameters", metricParams);
+            dbusIface.register_property("EmitsReadingsUpdate",
+                                        emitsReadingsSignal);
+            dbusIface.register_property("LogToMetricReportsCollection",
+                                        logToMetricReportsCollection);
+        });
+
+    deleteIface = objServer->add_unique_interface(
+        path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
+            dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
+                boost::asio::post(ioc, [this, &reportManager] {
+                    reportManager.removeReport(this);
+                });
+            });
+        });
+}
diff --git a/src/report.hpp b/src/report.hpp
new file mode 100644
index 0000000..7f74d49
--- /dev/null
+++ b/src/report.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <boost/asio/io_context.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <chrono>
+#include <memory>
+
+using Readings = std::tuple<
+    uint64_t,
+    std::vector<std::tuple<std::string, std::string, double, uint64_t>>>;
+using ReadingParameters =
+    std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
+                           std::string, std::string, std::string>>;
+
+class ReportManager;
+
+class Report
+{
+  public:
+    Report(boost::asio::io_context& ioc,
+           const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
+           const std::string& name, const std::string& reportingType,
+           const bool emitsReadingsSignal,
+           const bool logToMetricReportsCollection,
+           const std::chrono::milliseconds period,
+           const ReadingParameters& metricParams, ReportManager& reportManager);
+    ~Report() = default;
+
+    Report(Report&) = delete;
+    Report(Report&&) = delete;
+    Report& operator=(Report&) = delete;
+    Report& operator=(Report&&) = delete;
+
+    const std::string name;
+    const std::string path;
+
+  private:
+    std::chrono::milliseconds interval;
+    std::shared_ptr<sdbusplus::asio::object_server> objServer;
+    std::unique_ptr<sdbusplus::asio::dbus_interface> reportIface;
+    std::unique_ptr<sdbusplus::asio::dbus_interface> deleteIface;
+};
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index 9735abd..f2cbe94 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -1,5 +1,7 @@
 #include "report_manager.hpp"
 
+#include <sdbusplus/exception.hpp>
+
 #include <system_error>
 
 constexpr const char* reportManagerIfaceName =
@@ -8,23 +10,68 @@
     "/xyz/openbmc_project/Telemetry/Reports";
 
 ReportManager::ReportManager(
-    const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
-    objServer(objServer)
+    const std::shared_ptr<sdbusplus::asio::connection>& bus,
+    const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
+    objServer(objServerIn)
 {
-    reportManagerIntf =
-        objServer->add_interface(reportManagerPath, reportManagerIfaceName);
+    reports.reserve(maxReports);
 
-    reportManagerIntf->register_property_r(
-        "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_,
-        [](const auto&) { return maxReports; });
-    reportManagerIntf->register_property_r(
-        "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
-        [](const auto&) -> uint64_t { return minInterval.count(); });
+    reportManagerIface = objServer->add_unique_interface(
+        reportManagerPath, reportManagerIfaceName,
+        [this, &ioc = bus->get_io_context()](auto& dbusIface) {
+            dbusIface.register_property_r(
+                "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_,
+                [](const auto&) { return maxReports; });
+            dbusIface.register_property_r(
+                "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
+                [](const auto&) -> uint64_t { return minInterval.count(); });
 
-    reportManagerIntf->initialize();
+            dbusIface.register_method(
+                "AddReport",
+                [this, &ioc](const std::string& reportName,
+                             const std::string& reportingType,
+                             const bool emitsReadingsUpdate,
+                             const bool logToMetricReportsCollection,
+                             const uint64_t interval,
+                             const ReadingParameters& metricParams) {
+                    if (reports.size() >= maxReports)
+                    {
+                        throw sdbusplus::exception::SdBusError(
+                            static_cast<int>(std::errc::too_many_files_open),
+                            "Reached maximal report count");
+                    }
+
+                    for (const auto& report : reports)
+                    {
+                        if (report->name == reportName)
+                        {
+                            throw sdbusplus::exception::SdBusError(
+                                static_cast<int>(std::errc::file_exists),
+                                "Duplicate report");
+                        }
+                    }
+
+                    std::chrono::milliseconds reportInterval{interval};
+                    if (reportInterval < minInterval)
+                    {
+                        throw sdbusplus::exception::SdBusError(
+                            static_cast<int>(std::errc::invalid_argument),
+                            "Invalid interval");
+                    }
+
+                    reports.emplace_back(std::make_unique<Report>(
+                        ioc, objServer, reportName, reportingType,
+                        emitsReadingsUpdate, logToMetricReportsCollection,
+                        std::move(reportInterval), metricParams, *this));
+                    return reports.back()->path;
+                });
+        });
 }
 
-ReportManager::~ReportManager()
+void ReportManager::removeReport(const Report* report)
 {
-    objServer->remove_interface(reportManagerIntf);
+    reports.erase(
+        std::remove_if(reports.begin(), reports.end(),
+                       [report](const auto& x) { return report == x.get(); }),
+        reports.end());
 }
diff --git a/src/report_manager.hpp b/src/report_manager.hpp
index c01c34a..177a03c 100644
--- a/src/report_manager.hpp
+++ b/src/report_manager.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "report.hpp"
+
 #include <sdbusplus/asio/object_server.hpp>
 
 #include <chrono>
@@ -10,16 +12,24 @@
 {
   public:
     ReportManager(
+        const std::shared_ptr<sdbusplus::asio::connection>& bus,
         const std::shared_ptr<sdbusplus::asio::object_server>& objServer);
-    ~ReportManager();
+    ~ReportManager() = default;
 
-    ReportManager(const ReportManager&) = delete;
-    ReportManager& operator=(const ReportManager&) = delete;
+    ReportManager(ReportManager&) = delete;
+    ReportManager(ReportManager&&) = delete;
+    ReportManager& operator=(ReportManager&) = delete;
+    ReportManager& operator=(ReportManager&&) = delete;
+
+    static bool verifyScanPeriod(const uint64_t scanPeriod);
+    void removeReport(const Report* report);
 
   private:
     std::shared_ptr<sdbusplus::asio::object_server> objServer;
-    std::shared_ptr<sdbusplus::asio::dbus_interface> reportManagerIntf;
+    std::unique_ptr<sdbusplus::asio::dbus_interface> reportManagerIface;
+    std::vector<std::unique_ptr<Report>> reports;
 
+  public:
     static constexpr uint32_t maxReports{20};
     static constexpr std::chrono::milliseconds minInterval{1000};
 };
diff --git a/src/telemetry.hpp b/src/telemetry.hpp
index 0edcd2d..efdebaa 100644
--- a/src/telemetry.hpp
+++ b/src/telemetry.hpp
@@ -12,7 +12,7 @@
   public:
     Telemetry(std::shared_ptr<sdbusplus::asio::connection> bus) :
         objServer(std::make_shared<sdbusplus::asio::object_server>(bus)),
-        reportManager(objServer)
+        reportManager(bus, objServer)
     {}
 
   private: