blob: 9dbb91f4bc7d89184ed63d3b67cffed4701a1092 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
JunLin Chen28afb492021-02-24 17:13:29 +08003#pragma once
4#include "logging.hpp"
5
Ed Tanous601c71a2021-09-08 16:40:12 -07006#include <boost/beast/http/fields.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +08007#include <boost/container/flat_map.hpp>
Ed Tanousa716aa72023-08-01 11:35:53 -07008#include <boost/url/parse.hpp>
Ed Tanous4a7fbef2024-04-06 16:03:49 -07009#include <boost/url/url.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +080010#include <nlohmann/json.hpp>
11
Myung Bae5064a252024-10-04 09:34:25 -070012#include <limits>
Myung Bae56ba3862024-10-10 17:09:37 -070013#include <memory>
14#include <string>
15#include <vector>
16
JunLin Chen28afb492021-02-24 17:13:29 +080017namespace persistent_data
18{
19
20struct UserSubscription
21{
Ed Tanous4b712a22023-08-02 12:56:52 -070022 // Represents a Redfish EventDestination instance
JunLin Chen28afb492021-02-24 17:13:29 +080023 std::string id;
Ed Tanousa716aa72023-08-01 11:35:53 -070024 boost::urls::url destinationUrl;
JunLin Chen28afb492021-02-24 17:13:29 +080025 std::string protocol;
Ed Tanous19bb3622024-07-05 10:07:40 -050026 bool verifyCertificate = true;
JunLin Chen28afb492021-02-24 17:13:29 +080027 std::string retryPolicy;
Myung Bae5064a252024-10-04 09:34:25 -070028 bool sendHeartbeat = false;
29 // This value of hbIntervalMinutes is just a reasonable default value and
30 // most clients will update it if sendHeartbeat is turned on
31 uint64_t hbIntervalMinutes = 10;
JunLin Chen28afb492021-02-24 17:13:29 +080032 std::string customText;
33 std::string eventFormatType;
34 std::string subscriptionType;
35 std::vector<std::string> registryMsgIds;
36 std::vector<std::string> registryPrefixes;
37 std::vector<std::string> resourceTypes;
Ed Tanous601c71a2021-09-08 16:40:12 -070038 boost::beast::http::fields httpHeaders;
JunLin Chen28afb492021-02-24 17:13:29 +080039 std::vector<std::string> metricReportDefinitions;
Ed Tanousa14c9112024-09-04 10:46:47 -070040 std::vector<std::string> originResources;
JunLin Chen28afb492021-02-24 17:13:29 +080041
Ed Tanous4b712a22023-08-02 12:56:52 -070042 static std::optional<UserSubscription> fromJson(
Patrick Williamsbd79bce2024-08-16 15:22:20 -040043 const nlohmann::json::object_t& j, const bool loadFromOldConfig = false)
JunLin Chen28afb492021-02-24 17:13:29 +080044 {
Ed Tanous4b712a22023-08-02 12:56:52 -070045 UserSubscription subvalue;
Ed Tanous0bdda662023-08-03 17:27:34 -070046 for (const auto& element : j)
JunLin Chen28afb492021-02-24 17:13:29 +080047 {
Ed Tanous0bdda662023-08-03 17:27:34 -070048 if (element.first == "Id")
JunLin Chen28afb492021-02-24 17:13:29 +080049 {
50 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070051 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080052 if (value == nullptr)
53 {
54 continue;
55 }
Ed Tanous4b712a22023-08-02 12:56:52 -070056 subvalue.id = *value;
JunLin Chen28afb492021-02-24 17:13:29 +080057 }
Ed Tanous0bdda662023-08-03 17:27:34 -070058 else if (element.first == "Destination")
JunLin Chen28afb492021-02-24 17:13:29 +080059 {
60 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070061 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080062 if (value == nullptr)
63 {
64 continue;
65 }
Ed Tanous6fd29552023-10-04 09:40:14 -070066 boost::system::result<boost::urls::url> url =
Ed Tanousa716aa72023-08-01 11:35:53 -070067 boost::urls::parse_absolute_uri(*value);
68 if (!url)
69 {
70 continue;
71 }
Ed Tanous4b712a22023-08-02 12:56:52 -070072 subvalue.destinationUrl = std::move(*url);
JunLin Chen28afb492021-02-24 17:13:29 +080073 }
Ed Tanous0bdda662023-08-03 17:27:34 -070074 else if (element.first == "Protocol")
JunLin Chen28afb492021-02-24 17:13:29 +080075 {
76 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070077 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080078 if (value == nullptr)
79 {
80 continue;
81 }
Ed Tanous4b712a22023-08-02 12:56:52 -070082 subvalue.protocol = *value;
JunLin Chen28afb492021-02-24 17:13:29 +080083 }
Ed Tanous19bb3622024-07-05 10:07:40 -050084 else if (element.first == "VerifyCertificate")
85 {
86 const bool* value = element.second.get_ptr<const bool*>();
87 if (value == nullptr)
88 {
89 continue;
90 }
Ed Tanous4b712a22023-08-02 12:56:52 -070091 subvalue.verifyCertificate = *value;
Ed Tanous19bb3622024-07-05 10:07:40 -050092 }
Ed Tanous0bdda662023-08-03 17:27:34 -070093 else if (element.first == "DeliveryRetryPolicy")
JunLin Chen28afb492021-02-24 17:13:29 +080094 {
95 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070096 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080097 if (value == nullptr)
98 {
99 continue;
100 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700101 subvalue.retryPolicy = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800102 }
Myung Bae5064a252024-10-04 09:34:25 -0700103 else if (element.first == "SendHeartbeat")
104 {
105 const bool* value = element.second.get_ptr<const bool*>();
106 if (value == nullptr)
107 {
108 continue;
109 }
110 subvalue.sendHeartbeat = *value;
111 }
112 else if (element.first == "HeartbeatIntervalMinutes")
113 {
114 const uint64_t* value =
115 element.second.get_ptr<const uint64_t*>();
116 if (value == nullptr || *value < 1 || *value > 65535)
117 {
118 continue;
119 }
120 subvalue.hbIntervalMinutes = *value;
121 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700122 else if (element.first == "Context")
JunLin Chen28afb492021-02-24 17:13:29 +0800123 {
124 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700125 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800126 if (value == nullptr)
127 {
128 continue;
129 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700130 subvalue.customText = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800131 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700132 else if (element.first == "EventFormatType")
JunLin Chen28afb492021-02-24 17:13:29 +0800133 {
134 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700135 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800136 if (value == nullptr)
137 {
138 continue;
139 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700140 subvalue.eventFormatType = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800141 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700142 else if (element.first == "SubscriptionType")
JunLin Chen28afb492021-02-24 17:13:29 +0800143 {
144 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700145 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800146 if (value == nullptr)
147 {
148 continue;
149 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700150 subvalue.subscriptionType = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800151 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700152 else if (element.first == "MessageIds")
JunLin Chen28afb492021-02-24 17:13:29 +0800153 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700154 const nlohmann::json::array_t* obj =
155 element.second.get_ptr<const nlohmann::json::array_t*>();
156 if (obj == nullptr)
157 {
158 continue;
159 }
160 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800161 {
162 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700163 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800164 if (value == nullptr)
165 {
166 continue;
167 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700168 subvalue.registryMsgIds.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800169 }
170 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700171 else if (element.first == "RegistryPrefixes")
JunLin Chen28afb492021-02-24 17:13:29 +0800172 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700173 const nlohmann::json::array_t* obj =
174 element.second.get_ptr<const nlohmann::json::array_t*>();
175 if (obj == nullptr)
176 {
177 continue;
178 }
179 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800180 {
181 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700182 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800183 if (value == nullptr)
184 {
185 continue;
186 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700187 subvalue.registryPrefixes.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800188 }
189 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700190 else if (element.first == "ResourceTypes")
JunLin Chen28afb492021-02-24 17:13:29 +0800191 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700192 const nlohmann::json::array_t* obj =
193 element.second.get_ptr<const nlohmann::json::array_t*>();
194 if (obj == nullptr)
195 {
196 continue;
197 }
198 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800199 {
200 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700201 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800202 if (value == nullptr)
203 {
204 continue;
205 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700206 subvalue.resourceTypes.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800207 }
208 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700209 else if (element.first == "HttpHeaders")
JunLin Chen28afb492021-02-24 17:13:29 +0800210 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700211 const nlohmann::json::object_t* obj =
212 element.second.get_ptr<const nlohmann::json::object_t*>();
213 if (obj == nullptr)
214 {
215 continue;
216 }
217 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800218 {
Ed Tanous601c71a2021-09-08 16:40:12 -0700219 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700220 val.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800221 if (value == nullptr)
222 {
Ed Tanous62598e32023-07-17 17:06:25 -0700223 BMCWEB_LOG_ERROR("Failed to parse value for key{}",
Ed Tanous0bdda662023-08-03 17:27:34 -0700224 val.first);
JunLin Chen28afb492021-02-24 17:13:29 +0800225 continue;
226 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700227 subvalue.httpHeaders.set(val.first, *value);
JunLin Chen28afb492021-02-24 17:13:29 +0800228 }
229 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700230 else if (element.first == "MetricReportDefinitions")
JunLin Chen28afb492021-02-24 17:13:29 +0800231 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700232 const nlohmann::json::array_t* obj =
233 element.second.get_ptr<const nlohmann::json::array_t*>();
234 if (obj == nullptr)
235 {
236 continue;
237 }
238 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800239 {
240 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700241 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800242 if (value == nullptr)
243 {
244 continue;
245 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700246 subvalue.metricReportDefinitions.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800247 }
248 }
Ed Tanousa14c9112024-09-04 10:46:47 -0700249 else if (element.first == "OriginResources")
250 {
251 const nlohmann::json::array_t* obj =
252 element.second.get_ptr<const nlohmann::json::array_t*>();
253 if (obj == nullptr)
254 {
255 continue;
256 }
257 for (const auto& val : *obj)
258 {
259 const std::string* value =
260 val.get_ptr<const std::string*>();
261 if (value == nullptr)
262 {
263 continue;
264 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700265 subvalue.originResources.emplace_back(*value);
Ed Tanousa14c9112024-09-04 10:46:47 -0700266 }
267 }
JunLin Chen28afb492021-02-24 17:13:29 +0800268 else
269 {
Ed Tanous62598e32023-07-17 17:06:25 -0700270 BMCWEB_LOG_ERROR(
271 "Got unexpected property reading persistent file: {}",
Ed Tanous0bdda662023-08-03 17:27:34 -0700272 element.first);
JunLin Chen28afb492021-02-24 17:13:29 +0800273 continue;
274 }
275 }
276
Ed Tanous4b712a22023-08-02 12:56:52 -0700277 if ((subvalue.id.empty() && !loadFromOldConfig) ||
278 subvalue.destinationUrl.empty() || subvalue.protocol.empty() ||
279 subvalue.retryPolicy.empty() || subvalue.eventFormatType.empty() ||
280 subvalue.subscriptionType.empty())
JunLin Chen28afb492021-02-24 17:13:29 +0800281 {
Ed Tanous62598e32023-07-17 17:06:25 -0700282 BMCWEB_LOG_ERROR("Subscription missing required field "
283 "information, refusing to restore");
Ed Tanous4b712a22023-08-02 12:56:52 -0700284 return std::nullopt;
JunLin Chen28afb492021-02-24 17:13:29 +0800285 }
286
287 return subvalue;
288 }
289};
290
291struct EventServiceConfig
292{
293 bool enabled = true;
294 uint32_t retryAttempts = 3;
295 uint32_t retryTimeoutInterval = 30;
296
Ed Tanous0bdda662023-08-03 17:27:34 -0700297 void fromJson(const nlohmann::json::object_t& j)
JunLin Chen28afb492021-02-24 17:13:29 +0800298 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700299 for (const auto& element : j)
JunLin Chen28afb492021-02-24 17:13:29 +0800300 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700301 if (element.first == "ServiceEnabled")
JunLin Chen28afb492021-02-24 17:13:29 +0800302 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700303 const bool* value = element.second.get_ptr<const bool*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800304 if (value == nullptr)
305 {
306 continue;
307 }
308 enabled = *value;
309 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700310 else if (element.first == "DeliveryRetryAttempts")
JunLin Chen28afb492021-02-24 17:13:29 +0800311 {
312 const uint64_t* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700313 element.second.get_ptr<const uint64_t*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800314 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800315 (*value > std::numeric_limits<uint32_t>::max()))
316 {
317 continue;
318 }
319 retryAttempts = static_cast<uint32_t>(*value);
320 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700321 else if (element.first == "DeliveryRetryIntervalSeconds")
JunLin Chen28afb492021-02-24 17:13:29 +0800322 {
323 const uint64_t* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700324 element.second.get_ptr<const uint64_t*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800325 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800326 (*value > std::numeric_limits<uint32_t>::max()))
327 {
328 continue;
329 }
330 retryTimeoutInterval = static_cast<uint32_t>(*value);
331 }
332 }
333 }
334};
335
336class EventServiceStore
337{
338 public:
Myung Bae5fe4ef32024-10-19 09:56:02 -0400339 boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
JunLin Chen28afb492021-02-24 17:13:29 +0800340 subscriptionsConfigMap;
341 EventServiceConfig eventServiceConfig;
342
343 static EventServiceStore& getInstance()
344 {
345 static EventServiceStore eventServiceStore;
346 return eventServiceStore;
347 }
348
349 EventServiceConfig& getEventServiceConfig()
350 {
351 return eventServiceConfig;
352 }
JunLin Chen28afb492021-02-24 17:13:29 +0800353};
354
355} // namespace persistent_data