diff options
author | Wludzik, Jozef <jozef.wludzik@intel.com> | 2020-05-18 12:56:57 +0300 |
---|---|---|
committer | Krzysztof Grobelny <krzysztof.grobelny@intel.com> | 2021-03-30 13:16:24 +0300 |
commit | 4dbb8aea7651dc61a4dc384625567b34393742a2 (patch) | |
tree | 5abb1d082af91d51c2bd9b86da79ae11c96af362 /redfish-core/include | |
parent | 4df1bee0bdc9d71043b51872875d3d22b26ab68f (diff) | |
download | bmcweb-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.hpp | 2 | ||||
-rw-r--r-- | redfish-core/include/utils/time_utils.hpp | 138 |
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); |