Add Persistent Heartbeat subscription properties
This adds Heartbeat parameters to subscriptions so that the future
heartbeat implementation can use those parameters specified by the
schema [1][2][3].
- SendHeartbeat
- HeartbeatIntervalMinutes
Tested:
1. POST Subscription
- Create a subscription (e.g. via Redfish-Event-Listener) or like
```
curl -k -H "Content-Type: application/json" -X POST https://${bmc}/redfish/v1/EventService/Subscriptions \
-d '{
"Context": "Public",
"DeliveryRetryPolicy": "TerminateAfterRetries",
"Destination": "https://DESTINATION-IPADDR/Redfish-Evt-Listener",
"EventFormatType": "Event",
"HeartbeatIntervalMinutes": 2,
"HttpHeaders": [],
"MessageIds": [],
"MetricReportDefinitions": [],
"Protocol": "Redfish",
"RegistryPrefixes": [],
"ResourceTypes": [],
"SendHeartbeat": true,
"SubscriptionType": "RedfishEvent",
"VerifyCertificate": true
}'
```
2. GET the subscription and check the content
```
SUBID=<id>
curl -k -X GET https://${bmc}/redfish/v1/EventService/Subscriptions/${SUBID}
```
3. PATCH Subscription
- PATCH with various SendHeartbeat & HeartbeatIntervalMinutes
For example,
```
curl -k -X PATCH https://${bmc}/redfish/v1/EventService/Subscriptions/${SUBID} \
-H "Content-Type: application/json" \
-d '{"SendHeartbeat":true, "HeartbeatIntervalMinutes":10}'
```
- Restart bmcweb or reboot BMC
- Get the subscription data and see whether the heartbeat properties are
persistent.
4. Redfish Validator Service passes
[1] https://github.com/openbmc/bmcweb/blob/d109e2b60f7bb367dc8115475c6cb86bca6e1914/redfish-core/schema/dmtf/json-schema/EventDestination.v1_15_0.json#L356
[2] https://github.com/openbmc/bmcweb/blob/d109e2b60f7bb367dc8115475c6cb86bca6e1914/redfish-core/schema/dmtf/json-schema/EventDestination.v1_15_0.json#L222
[3] https://www.dmtf.org/sites/default/files/standards/documents/DSP2046_2022.3.html
Change-Id: I9e7feadb2e851ca320147df2231f65ece58ddf25
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index d415496..04ca735 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -34,6 +34,7 @@
#include <charconv>
#include <memory>
+#include <optional>
#include <ranges>
#include <span>
#include <string>
@@ -299,6 +300,8 @@
std::optional<std::string> subscriptionType;
std::optional<std::string> eventFormatType2;
std::optional<std::string> retryPolicy;
+ std::optional<bool> sendHeartbeat;
+ std::optional<uint64_t> hbIntervalMinutes;
std::optional<std::vector<std::string>> msgIds;
std::optional<std::vector<std::string>> regPrefixes;
std::optional<std::vector<std::string>> originResources;
@@ -312,6 +315,7 @@
"DeliveryRetryPolicy", retryPolicy, //
"Destination", destUrl, //
"EventFormatType", eventFormatType2, //
+ "HeartbeatIntervalMinutes", hbIntervalMinutes, //
"HttpHeaders", headers, //
"MessageIds", msgIds, //
"MetricReportDefinitions", mrdJsonArray, //
@@ -319,6 +323,7 @@
"Protocol", protocol, //
"RegistryPrefixes", regPrefixes, //
"ResourceTypes", resTypes, //
+ "SendHeartbeat", sendHeartbeat, //
"SubscriptionType", subscriptionType, //
"VerifyCertificate", verifyCertificate //
))
@@ -403,6 +408,18 @@
"RetryPolicy", "Protocol");
return;
}
+ if (sendHeartbeat)
+ {
+ messages::propertyValueConflict(
+ asyncResp->res, "SendHeartbeat", "Protocol");
+ return;
+ }
+ if (hbIntervalMinutes)
+ {
+ messages::propertyValueConflict(
+ asyncResp->res, "HeartbeatIntervalMinutes", "Protocol");
+ return;
+ }
if (msgIds)
{
messages::propertyValueConflict(asyncResp->res,
@@ -646,6 +663,21 @@
// Default "TerminateAfterRetries"
subValue->userSub->retryPolicy = "TerminateAfterRetries";
}
+ if (sendHeartbeat)
+ {
+ subValue->userSub->sendHeartbeat = *sendHeartbeat;
+ }
+ if (hbIntervalMinutes)
+ {
+ if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
+ {
+ messages::propertyValueOutOfRange(
+ asyncResp->res, *hbIntervalMinutes,
+ "HeartbeatIntervalMinutes");
+ return;
+ }
+ subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
+ }
if (mrdJsonArray)
{
@@ -730,6 +762,8 @@
jVal["MessageIds"] = userSub.registryMsgIds;
jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
+ jVal["SendHeartbeat"] = userSub.sendHeartbeat;
+ jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes;
jVal["VerifyCertificate"] = userSub.verifyCertificate;
nlohmann::json::array_t mrdJsonArray;
@@ -766,6 +800,8 @@
std::optional<std::string> context;
std::optional<std::string> retryPolicy;
+ std::optional<bool> sendHeartbeat;
+ std::optional<uint64_t> hbIntervalMinutes;
std::optional<bool> verifyCertificate;
std::optional<std::vector<nlohmann::json::object_t>> headers;
@@ -773,7 +809,9 @@
req, asyncResp->res, //
"Context", context, //
"DeliveryRetryPolicy", retryPolicy, //
+ "HeartbeatIntervalMinutes", hbIntervalMinutes, //
"HttpHeaders", headers, //
+ "SendHeartbeat", sendHeartbeat, //
"VerifyCertificate", verifyCertificate //
))
{
@@ -821,6 +859,22 @@
subValue->userSub->retryPolicy = *retryPolicy;
}
+ if (sendHeartbeat)
+ {
+ subValue->userSub->sendHeartbeat = *sendHeartbeat;
+ }
+ if (hbIntervalMinutes)
+ {
+ if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
+ {
+ messages::propertyValueOutOfRange(
+ asyncResp->res, *hbIntervalMinutes,
+ "HeartbeatIntervalMinutes");
+ return;
+ }
+ subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
+ }
+
if (verifyCertificate)
{
subValue->userSub->verifyCertificate = *verifyCertificate;