summaryrefslogtreecommitdiff
path: root/redfish-core/include
diff options
context:
space:
mode:
authorWludzik, Jozef <jozef.wludzik@intel.com>2020-05-18 12:56:57 +0300
committerKrzysztof Grobelny <krzysztof.grobelny@intel.com>2021-03-30 13:16:24 +0300
commit4dbb8aea7651dc61a4dc384625567b34393742a2 (patch)
tree5abb1d082af91d51c2bd9b86da79ae11c96af362 /redfish-core/include
parent4df1bee0bdc9d71043b51872875d3d22b26ab68f (diff)
downloadbmcweb-4dbb8aea7651dc61a4dc384625567b34393742a2.tar.xz
Add POST and DELETE in MetricReportDefinitions
Added POST action in MetricReportDefinitions node to allow user to add new MetricReportDefinition. Using minimal set of MetricReportDefinition parameters from user bmcweb converts it to DBus call "AddReport" to Telemetry that serves as a backend for Redfish TelemetryService. Added DELETE request in MetricReportDefinitions node to allow user to remove report from Telemetry. Added conversion from string that represents duration format into its numeric equivalent. Added unit tests for conversion from and to Duration format. Tested: - Tested using witherspoon image on QEMU - Verified POST action in different cases: - all parameters are provided, new report is added to collection - some parameters are missing or invalid, user gets response with description of the issue - Verified that reports are removed on DELETE request - Verified that on invalid DELETE request user receives response with error - Verified time_utils::fromDurationString() - Succesfully passed RedfishServiceValidator.py Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> Change-Id: I2fed96848594451e22fde686f8c066d7770cc65a
Diffstat (limited to 'redfish-core/include')
-rw-r--r--redfish-core/include/utils/telemetry_utils.hpp2
-rw-r--r--redfish-core/include/utils/time_utils.hpp138
2 files changed, 138 insertions, 2 deletions
diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
index a3a8156e5a..0a3af5ffa0 100644
--- a/redfish-core/include/utils/telemetry_utils.hpp
+++ b/redfish-core/include/utils/telemetry_utils.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "dbus_utility.hpp"
+
namespace redfish
{
diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
index 4a87ba0d6c..9965d4de3b 100644
--- a/redfish-core/include/utils/time_utils.hpp
+++ b/redfish-core/include/utils/time_utils.hpp
@@ -1,7 +1,13 @@
#pragma once
+#include "logging.hpp"
+
+#include <charconv>
#include <chrono>
+#include <cmath>
+#include <optional>
#include <string>
+#include <system_error>
namespace redfish
{
@@ -12,6 +18,8 @@ namespace time_utils
namespace details
{
+using Days = std::chrono::duration<long long, std::ratio<24 * 60 * 60>>;
+
inline void leftZeroPadding(std::string& str, const std::size_t padding)
{
if (str.size() < padding)
@@ -19,9 +27,136 @@ inline void leftZeroPadding(std::string& str, const std::size_t padding)
str.insert(0, padding - str.size(), '0');
}
}
+
+template <typename FromTime>
+bool fromDurationItem(std::string_view& fmt, const char postfix,
+ std::chrono::milliseconds& out)
+{
+ const size_t pos = fmt.find(postfix);
+ if (pos == std::string::npos)
+ {
+ return true;
+ }
+ if ((pos + 1U) > fmt.size())
+ {
+ return false;
+ }
+
+ const char* end;
+ std::chrono::milliseconds::rep ticks = 0;
+ if constexpr (std::is_same_v<FromTime, std::chrono::milliseconds>)
+ {
+ end = fmt.data() + std::min<size_t>(pos, 3U);
+ }
+ else
+ {
+ end = fmt.data() + pos;
+ }
+
+ auto [ptr, ec] = std::from_chars(fmt.data(), end, ticks);
+ if (ptr != end || ec != std::errc())
+ {
+ BMCWEB_LOG_ERROR << "Failed to convert string to decimal with err: "
+ << static_cast<int>(ec) << "("
+ << std::make_error_code(ec).message() << "), ptr{"
+ << static_cast<const void*>(ptr) << "} != end{"
+ << static_cast<const void*>(end) << "})";
+ return false;
+ }
+
+ if constexpr (std::is_same_v<FromTime, std::chrono::milliseconds>)
+ {
+ ticks *= static_cast<std::chrono::milliseconds::rep>(
+ std::pow(10, 3 - std::min<size_t>(pos, 3U)));
+ }
+ if (ticks < 0)
+ {
+ return false;
+ }
+
+ out += FromTime(ticks);
+ const auto maxConversionRange =
+ std::chrono::duration_cast<FromTime>(std::chrono::milliseconds::max())
+ .count();
+ if (out < FromTime(ticks) || maxConversionRange < ticks)
+ {
+ return false;
+ }
+
+ fmt.remove_prefix(pos + 1U);
+ return true;
+}
} // namespace details
/**
+ * @brief Convert string that represents value in Duration Format to its numeric
+ * equivalent.
+ */
+std::optional<std::chrono::milliseconds>
+ fromDurationString(const std::string& str)
+{
+ std::chrono::milliseconds out = std::chrono::milliseconds::zero();
+ std::string_view v = str;
+
+ if (v.empty())
+ {
+ return out;
+ }
+ if (v.front() != 'P')
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+
+ v.remove_prefix(1);
+ if (!details::fromDurationItem<details::Days>(v, 'D', out))
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+
+ if (v.empty())
+ {
+ return out;
+ }
+ if (v.front() != 'T')
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+
+ v.remove_prefix(1);
+ if (!details::fromDurationItem<std::chrono::hours>(v, 'H', out) ||
+ !details::fromDurationItem<std::chrono::minutes>(v, 'M', out))
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+
+ if (v.find('.') != std::string::npos && v.find('S') != std::string::npos)
+ {
+ if (!details::fromDurationItem<std::chrono::seconds>(v, '.', out) ||
+ !details::fromDurationItem<std::chrono::milliseconds>(v, 'S', out))
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+ }
+ else if (!details::fromDurationItem<std::chrono::seconds>(v, 'S', out))
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+
+ if (!v.empty())
+ {
+ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
+ return std::nullopt;
+ }
+ return out;
+}
+
+/**
* @brief Convert time value into duration format that is based on ISO 8601.
* Example output: "P12DT1M5.5S"
* Ref: Redfish Specification, Section 9.4.4. Duration values
@@ -36,8 +171,7 @@ inline std::string toDurationString(std::chrono::milliseconds ms)
std::string fmt;
fmt.reserve(sizeof("PxxxxxxxxxxxxDTxxHxxMxx.xxxxxxS"));
- using Days = std::chrono::duration<long, std::ratio<24 * 60 * 60>>;
- Days days = std::chrono::floor<Days>(ms);
+ details::Days days = std::chrono::floor<details::Days>(ms);
ms -= days;
std::chrono::hours hours = std::chrono::floor<std::chrono::hours>(ms);