blob: e40d9a44bc4ae0e660a0795b265bce99b86b0bde [file] [log] [blame]
#include "report_manager.hpp"
#include "report.hpp"
#include "types/report_types.hpp"
#include "utils/conversion.hpp"
#include "utils/transform.hpp"
#include <phosphor-logging/log.hpp>
#include <sdbusplus/exception.hpp>
#include <stdexcept>
#include <system_error>
ReadingParameters
convertToReadingParameters(ReadingParametersPastVersion params)
{
return utils::transform(params, [](const auto& param) {
using namespace std::chrono_literals;
return ReadingParameters::value_type(
std::vector{{std::get<0>(param)}}, std::get<1>(param),
std::get<2>(param), std::get<3>(param),
utils::enumToString(CollectionTimeScope::point), 0u);
});
}
ReportManager::ReportManager(
std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
reportFactory(std::move(reportFactoryIn)),
reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
{
reports.reserve(maxReports);
loadFromPersistent();
reportManagerIface = objServer->add_unique_interface(
reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
dbusIface.register_property_r(
"MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
[](const auto&) { return maxReports; });
dbusIface.register_property_r(
"MaxReportNameLength", size_t{},
sdbusplus::vtable::property_::const_,
[](const auto&) { return maxReportNameLength; });
dbusIface.register_property_r(
"MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
[](const auto&) -> uint64_t { return minInterval.count(); });
dbusIface.register_method(
"AddReport", [this](boost::asio::yield_context& yield,
const std::string& reportName,
const std::string& reportingType,
const bool emitsReadingsUpdate,
const bool logToMetricReportsCollection,
const uint64_t interval,
ReadingParametersPastVersion metricParams) {
return addReport(yield, reportName, reportingType,
emitsReadingsUpdate,
logToMetricReportsCollection,
Milliseconds(interval),
convertToReadingParameters(
std::move(metricParams)))
.getPath();
});
dbusIface.register_method(
"AddReportFutureVersion",
[this](boost::asio::yield_context& yield,
const std::string& reportName,
const std::string& reportingType,
const bool emitsReadingsUpdate,
const bool logToMetricReportsCollection,
const uint64_t interval,
ReadingParameters metricParams) {
return addReport(yield, reportName, reportingType,
emitsReadingsUpdate,
logToMetricReportsCollection,
Milliseconds(interval),
std::move(metricParams))
.getPath();
});
});
}
void ReportManager::removeReport(const interfaces::Report* report)
{
reports.erase(
std::remove_if(reports.begin(), reports.end(),
[report](const auto& x) { return report == x.get(); }),
reports.end());
}
void ReportManager::verifyReportNameLength(const std::string& reportName)
{
if (reportName.length() > maxReportNameLength)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument),
"Report name exceed maximum length");
}
}
void ReportManager::verifyAddReport(
const std::string& reportName, const std::string& reportingType,
Milliseconds interval,
const std::vector<LabeledMetricParameters>& readingParams)
{
if (reports.size() >= maxReports)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::too_many_files_open),
"Reached maximal report count");
}
verifyReportNameLength(reportName);
for (const auto& report : reports)
{
if (report->getName() == reportName)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::file_exists), "Duplicate report");
}
}
auto found = std::find(supportedReportingType.begin(),
supportedReportingType.end(), reportingType);
if (found == supportedReportingType.end())
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument),
"Invalid reportingType");
}
if (reportingType == "Periodic" && interval < minInterval)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument), "Invalid interval");
}
if (readingParams.size() > maxReadingParams)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::argument_list_too_long),
"Too many reading parameters");
}
try
{
namespace ts = utils::tstring;
for (const LabeledMetricParameters& item : readingParams)
{
utils::toOperationType(
utils::toUnderlying(item.at_label<ts::OperationType>()));
}
}
catch (const std::exception& e)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument), e.what());
}
}
interfaces::Report& ReportManager::addReport(
boost::asio::yield_context& yield, const std::string& reportName,
const std::string& reportingType, const bool emitsReadingsUpdate,
const bool logToMetricReportsCollection, Milliseconds interval,
ReadingParameters metricParams)
{
auto labeledMetricParams =
reportFactory->convertMetricParams(yield, metricParams);
return addReport(reportName, reportingType, emitsReadingsUpdate,
logToMetricReportsCollection, interval,
std::move(labeledMetricParams));
}
interfaces::Report& ReportManager::addReport(
const std::string& reportName, const std::string& reportingType,
const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
Milliseconds interval,
std::vector<LabeledMetricParameters> labeledMetricParams)
{
verifyAddReport(reportName, reportingType, interval, labeledMetricParams);
reports.emplace_back(
reportFactory->make(reportName, reportingType, emitsReadingsUpdate,
logToMetricReportsCollection, interval, *this,
*reportStorage, labeledMetricParams));
return *reports.back();
}
void ReportManager::loadFromPersistent()
{
std::vector<interfaces::JsonStorage::FilePath> paths =
reportStorage->list();
for (const auto& path : paths)
{
std::optional<nlohmann::json> data = reportStorage->load(path);
try
{
size_t version = data->at("Version").get<size_t>();
if (version != Report::reportVersion)
{
throw std::logic_error("Invalid version");
}
std::string& name = data->at("Name").get_ref<std::string&>();
std::string& reportingType =
data->at("ReportingType").get_ref<std::string&>();
bool emitsReadingsSignal =
data->at("EmitsReadingsUpdate").get<bool>();
bool logToMetricReportsCollection =
data->at("LogToMetricReportsCollection").get<bool>();
uint64_t interval = data->at("Interval").get<uint64_t>();
auto readingParameters =
data->at("ReadingParameters")
.get<std::vector<LabeledMetricParameters>>();
addReport(name, reportingType, emitsReadingsSignal,
logToMetricReportsCollection, Milliseconds(interval),
std::move(readingParameters));
}
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Failed to load report from storage",
phosphor::logging::entry(
"FILENAME=%s",
static_cast<std::filesystem::path>(path).c_str()),
phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
reportStorage->remove(path);
}
}
}
void ReportManager::updateReport(const std::string& name)
{
for (auto& report : reports)
{
if (report->getName() == name)
{
report->updateReadings();
return;
}
}
}