blob: 7510f0f0210b12278d2737a5412aee52702b117c [file] [log] [blame]
AppaRao Pulie5aaf042020-03-20 01:05:52 +05301/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2020 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
AppaRao Pulie5aaf042020-03-20 01:05:52 +053015*/
16#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include "app.hpp"
AppaRao Pulib52664e2020-04-09 21:36:51 +053018#include "event_service_manager.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070019#include "generated/enums/event_service.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "http/utility.hpp"
21#include "logging.hpp"
22#include "query.hpp"
23#include "registries/privilege_registry.hpp"
Chicago Duan3d307082020-11-26 14:12:12 +080024#include "snmp_trap_event_clients.hpp"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053025
Ed Tanous601c71a2021-09-08 16:40:12 -070026#include <boost/beast/http/fields.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080027#include <boost/system/error_code.hpp>
Ed Tanousa716aa72023-08-01 11:35:53 -070028#include <boost/url/parse.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080029#include <sdbusplus/unpack_properties.hpp>
30#include <utils/dbus_utils.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070031
Chicago Duan3d307082020-11-26 14:12:12 +080032#include <charconv>
33#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070034#include <ranges>
Patrick Williams1e270c52021-12-04 06:06:56 -060035#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080036#include <string>
Ed Tanousa14c9112024-09-04 10:46:47 -070037#include <vector>
Patrick Williams1e270c52021-12-04 06:06:56 -060038
AppaRao Pulie5aaf042020-03-20 01:05:52 +053039namespace redfish
40{
41
AppaRao Puli156d6b02020-04-25 06:04:05 +053042static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
43 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053044static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053045 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053046static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
47 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
48
Sunitha Harishe56f2542020-07-22 02:38:59 -050049static constexpr const std::array<const char*, 1> supportedResourceTypes = {
50 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050051
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053053{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070054 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070055 .privileges(redfish::privileges::getEventService)
Patrick Williamsbd79bce2024-08-16 15:22:20 -040056 .methods(
57 boost::beast::http::verb::
58 get)([&app](
59 const crow::Request& req,
60 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
61 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
62 {
63 return;
64 }
Ed Tanous14766872022-03-15 10:44:42 -070065
Patrick Williamsbd79bce2024-08-16 15:22:20 -040066 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
67 asyncResp->res.jsonValue["@odata.type"] =
68 "#EventService.v1_5_0.EventService";
69 asyncResp->res.jsonValue["Id"] = "EventService";
70 asyncResp->res.jsonValue["Name"] = "Event Service";
71 asyncResp->res.jsonValue["ServerSentEventUri"] =
72 "/redfish/v1/EventService/SSE";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000073
Patrick Williamsbd79bce2024-08-16 15:22:20 -040074 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
75 "/redfish/v1/EventService/Subscriptions";
76 asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
77 ["target"] =
78 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053079
Patrick Williamsbd79bce2024-08-16 15:22:20 -040080 const persistent_data::EventServiceConfig eventServiceConfig =
81 persistent_data::EventServiceStore::getInstance()
82 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080083
Patrick Williamsbd79bce2024-08-16 15:22:20 -040084 asyncResp->res.jsonValue["Status"]["State"] =
85 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
86 asyncResp->res.jsonValue["ServiceEnabled"] =
87 eventServiceConfig.enabled;
88 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
89 eventServiceConfig.retryAttempts;
90 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
91 eventServiceConfig.retryTimeoutInterval;
92 asyncResp->res.jsonValue["EventFormatTypes"] =
93 supportedEvtFormatTypes;
94 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
95 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053096
Patrick Williamsbd79bce2024-08-16 15:22:20 -040097 nlohmann::json::object_t supportedSSEFilters;
98 supportedSSEFilters["EventFormatType"] = true;
99 supportedSSEFilters["MessageId"] = true;
100 supportedSSEFilters["MetricReportDefinition"] = true;
101 supportedSSEFilters["RegistryPrefix"] = true;
102 supportedSSEFilters["OriginResource"] = false;
103 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530104
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400105 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
106 std::move(supportedSSEFilters);
107 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530108
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700109 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700110 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700111 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700112 [&app](const crow::Request& req,
113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400114 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115 {
116 return;
117 }
118 std::optional<bool> serviceEnabled;
119 std::optional<uint32_t> retryAttemps;
120 std::optional<uint32_t> retryInterval;
Myung Baeafc474a2024-10-09 00:53:29 -0700121 if (!json_util::readJsonPatch( //
122 req, asyncResp->res, //
123 "DeliveryRetryAttempts", retryAttemps, //
124 "DeliveryRetryIntervalSeconds", retryInterval, //
125 "ServiceEnabled", serviceEnabled //
126 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400127 {
128 return;
129 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530130
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400131 persistent_data::EventServiceConfig eventServiceConfig =
132 persistent_data::EventServiceStore::getInstance()
133 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700134
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400135 if (serviceEnabled)
136 {
137 eventServiceConfig.enabled = *serviceEnabled;
138 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500139
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400140 if (retryAttemps)
141 {
142 // Supported range [1-3]
143 if ((*retryAttemps < 1) || (*retryAttemps > 3))
144 {
145 messages::queryParameterOutOfRange(
146 asyncResp->res, std::to_string(*retryAttemps),
147 "DeliveryRetryAttempts", "[1-3]");
148 }
149 else
150 {
151 eventServiceConfig.retryAttempts = *retryAttemps;
152 }
153 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530154
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400155 if (retryInterval)
156 {
157 // Supported range [5 - 180]
158 if ((*retryInterval < 5) || (*retryInterval > 180))
159 {
160 messages::queryParameterOutOfRange(
161 asyncResp->res, std::to_string(*retryInterval),
162 "DeliveryRetryIntervalSeconds", "[5-180]");
163 }
164 else
165 {
166 eventServiceConfig.retryTimeoutInterval =
167 *retryInterval;
168 }
169 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400171 EventServiceManager::getInstance().setEventServiceConfig(
172 eventServiceConfig);
173 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700174}
175
176inline void requestRoutesSubmitTestEvent(App& app)
177{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700178 BMCWEB_ROUTE(
179 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700180 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700181 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700182 [&app](const crow::Request& req,
183 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400184 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
185 {
186 return;
187 }
188 if (!EventServiceManager::getInstance().sendTestEventLog())
189 {
190 messages::serviceDisabled(asyncResp->res,
191 "/redfish/v1/EventService/");
192 return;
193 }
194 asyncResp->res.result(boost::beast::http::status::no_content);
195 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700196}
197
Chicago Duan3d307082020-11-26 14:12:12 +0800198inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700199 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
201 const dbus::utility::ManagedObjectType& resp)
202{
203 if (ec)
204 {
Ed Tanous13061012023-07-25 11:12:19 -0700205 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800206 {
207 // This is an optional process so just return if it isn't there
208 return;
209 }
210
Ed Tanous62598e32023-07-17 17:06:25 -0700211 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800212 messages::internalError(asyncResp->res);
213 return;
214 }
215 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
216 for (const auto& objpath : resp)
217 {
218 sdbusplus::message::object_path path(objpath.first);
219 const std::string snmpId = path.filename();
220 if (snmpId.empty())
221 {
Ed Tanous62598e32023-07-17 17:06:25 -0700222 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800223 messages::internalError(asyncResp->res);
224 return;
225 }
226
227 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
228 }
229}
230
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700231inline void requestRoutesEventDestinationCollection(App& app)
232{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000233 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700234 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700235 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700236 [&app](const crow::Request& req,
237 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400238 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
239 {
240 return;
241 }
242 asyncResp->res.jsonValue["@odata.type"] =
243 "#EventDestinationCollection.EventDestinationCollection";
244 asyncResp->res.jsonValue["@odata.id"] =
245 "/redfish/v1/EventService/Subscriptions";
246 asyncResp->res.jsonValue["Name"] =
247 "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700248
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400249 nlohmann::json& memberArray =
250 asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700251
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400252 std::vector<std::string> subscripIds =
253 EventServiceManager::getInstance().getAllIDs();
254 memberArray = nlohmann::json::array();
255 asyncResp->res.jsonValue["Members@odata.count"] =
256 subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700257
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400258 for (const std::string& id : subscripIds)
259 {
260 nlohmann::json::object_t member;
261 member["@odata.id"] = boost::urls::format(
262 "/redfish/v1/EventService/Subscriptions/{}" + id);
263 memberArray.emplace_back(std::move(member));
264 }
265 crow::connections::systemBus->async_method_call(
266 [asyncResp](const boost::system::error_code& ec,
267 const dbus::utility::ManagedObjectType& resp) {
268 doSubscriptionCollection(ec, asyncResp, resp);
269 },
270 "xyz.openbmc_project.Network.SNMP",
271 "/xyz/openbmc_project/network/snmp/manager",
272 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
273 });
Chicago Duan3d307082020-11-26 14:12:12 +0800274
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700275 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500276 .privileges(redfish::privileges::postEventDestinationCollection)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400277 .methods(
278 boost::beast::http::verb::
279 post)([&app](
280 const crow::Request& req,
281 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
282 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
283 {
284 return;
285 }
286 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
287 maxNoOfSubscriptions)
288 {
289 messages::eventSubscriptionLimitExceeded(asyncResp->res);
290 return;
291 }
292 std::string destUrl;
293 std::string protocol;
294 std::optional<bool> verifyCertificate;
295 std::optional<std::string> context;
296 std::optional<std::string> subscriptionType;
297 std::optional<std::string> eventFormatType2;
298 std::optional<std::string> retryPolicy;
299 std::optional<std::vector<std::string>> msgIds;
300 std::optional<std::vector<std::string>> regPrefixes;
Ed Tanousa14c9112024-09-04 10:46:47 -0700301 std::optional<std::vector<std::string>> originResources;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 std::optional<std::vector<std::string>> resTypes;
303 std::optional<std::vector<nlohmann::json::object_t>> headers;
304 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800305
Myung Baeafc474a2024-10-09 00:53:29 -0700306 if (!json_util::readJsonPatch( //
307 req, asyncResp->res, //
308 "Context", context, //
309 "DeliveryRetryPolicy", retryPolicy, //
310 "Destination", destUrl, //
311 "EventFormatType", eventFormatType2, //
312 "HttpHeaders", headers, //
313 "MessageIds", msgIds, //
314 "MetricReportDefinitions", mrdJsonArray, //
315 "OriginResources", originResources, //
316 "Protocol", protocol, //
317 "RegistryPrefixes", regPrefixes, //
318 "ResourceTypes", resTypes, //
319 "SubscriptionType", subscriptionType, //
320 "VerifyCertificate", verifyCertificate //
321 ))
Ed Tanousfffb8c12022-02-07 23:53:03 -0800322 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700323 return;
324 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700325 // clang-format on
Chicago Duan3d307082020-11-26 14:12:12 +0800326
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400327 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
328 static constexpr const uint16_t maxDestinationSize = 2000;
329 if (destUrl.size() > maxDestinationSize)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800330 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400331 messages::stringValueTooLong(asyncResp->res, "Destination",
332 maxDestinationSize);
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 return;
334 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700335
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400336 if (regPrefixes && msgIds)
Ed Tanous002d39b2022-05-31 08:59:27 -0700337 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400338 if (!regPrefixes->empty() && !msgIds->empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700339 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400340 messages::propertyValueConflict(
341 asyncResp->res, "MessageIds", "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530342 return;
343 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800344 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530345
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400346 boost::system::result<boost::urls::url> url =
347 boost::urls::parse_absolute_uri(destUrl);
348 if (!url)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800349 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400350 BMCWEB_LOG_WARNING(
351 "Failed to validate and split destination url");
352 messages::propertyValueFormatError(asyncResp->res, destUrl,
353 "Destination");
354 return;
355 }
356 url->normalize();
George Liub07942e2024-11-01 09:59:40 +0800357
358 // port_number returns zero if it is not a valid representable port
359 if (url->has_port() && url->port_number() == 0)
360 {
361 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
362 url->port());
363 messages::propertyValueFormatError(asyncResp->res, destUrl,
364 "Destination");
365 return;
366 }
367
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400368 crow::utility::setProtocolDefaults(*url, protocol);
369 crow::utility::setPortDefaults(*url);
370
371 if (url->path().empty())
372 {
373 url->set_path("/");
374 }
375
376 if (url->has_userinfo())
377 {
378 messages::propertyValueFormatError(asyncResp->res, destUrl,
379 "Destination");
380 return;
381 }
382
383 if (protocol == "SNMPv2c")
384 {
385 if (context)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700386 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400387 messages::propertyValueConflict(asyncResp->res, "Context",
388 "Protocol");
AppaRao Puli144b6312020-08-03 22:23:12 +0530389 return;
390 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400391 if (eventFormatType2)
392 {
393 messages::propertyValueConflict(
394 asyncResp->res, "EventFormatType", "Protocol");
395 return;
396 }
397 if (retryPolicy)
398 {
399 messages::propertyValueConflict(asyncResp->res,
400 "RetryPolicy", "Protocol");
401 return;
402 }
403 if (msgIds)
404 {
405 messages::propertyValueConflict(asyncResp->res,
406 "MessageIds", "Protocol");
407 return;
408 }
409 if (regPrefixes)
410 {
411 messages::propertyValueConflict(
412 asyncResp->res, "RegistryPrefixes", "Protocol");
413 return;
414 }
415 if (resTypes)
416 {
417 messages::propertyValueConflict(
418 asyncResp->res, "ResourceTypes", "Protocol");
419 return;
420 }
421 if (headers)
422 {
423 messages::propertyValueConflict(asyncResp->res,
424 "HttpHeaders", "Protocol");
425 return;
426 }
427 if (mrdJsonArray)
428 {
429 messages::propertyValueConflict(
430 asyncResp->res, "MetricReportDefinitions", "Protocol");
431 return;
432 }
433 if (url->scheme() != "snmp")
434 {
435 messages::propertyValueConflict(asyncResp->res,
436 "Destination", "Protocol");
437 return;
438 }
439
440 addSnmpTrapClient(asyncResp, url->host_address(),
441 url->port_number());
442 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700444
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400445 std::shared_ptr<Subscription> subValue =
Myung Bae21a94d52024-10-14 15:02:57 -0700446 std::make_shared<Subscription>(
447 persistent_data::UserSubscription{}, *url, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700448
Ed Tanous4b712a22023-08-02 12:56:52 -0700449 subValue->userSub.destinationUrl = std::move(*url);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400450
451 if (subscriptionType)
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400453 if (*subscriptionType != "RedfishEvent")
454 {
455 messages::propertyValueNotInList(
456 asyncResp->res, *subscriptionType, "SubscriptionType");
457 return;
458 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700459 subValue->userSub.subscriptionType = *subscriptionType;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800460 }
461 else
462 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700463 // Default
464 subValue->userSub.subscriptionType = "RedfishEvent";
Ed Tanousfffb8c12022-02-07 23:53:03 -0800465 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530466
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400467 if (protocol != "Redfish")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800468 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400469 messages::propertyValueNotInList(asyncResp->res, protocol,
470 "Protocol");
471 return;
472 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700473 subValue->userSub.protocol = protocol;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800474
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400475 if (verifyCertificate)
476 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700477 subValue->userSub.verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400478 }
479
480 if (eventFormatType2)
481 {
482 if (std::ranges::find(supportedEvtFormatTypes,
483 *eventFormatType2) ==
484 supportedEvtFormatTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700485 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400486 messages::propertyValueNotInList(
487 asyncResp->res, *eventFormatType2, "EventFormatType");
488 return;
489 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700490 subValue->userSub.eventFormatType = *eventFormatType2;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400491 }
492 else
493 {
494 // If not specified, use default "Event"
Ed Tanous4b712a22023-08-02 12:56:52 -0700495 subValue->userSub.eventFormatType = "Event";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400496 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700497
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400498 if (context)
499 {
500 // This value is selected arbitrarily.
501 constexpr const size_t maxContextSize = 256;
502 if (context->size() > maxContextSize)
503 {
504 messages::stringValueTooLong(asyncResp->res, "Context",
505 maxContextSize);
506 return;
507 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700508 subValue->userSub.customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400509 }
510
511 if (headers)
512 {
513 size_t cumulativeLen = 0;
514
515 for (const nlohmann::json::object_t& headerChunk : *headers)
516 {
517 for (const auto& item : headerChunk)
Ed Tanous002d39b2022-05-31 08:59:27 -0700518 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400519 const std::string* value =
520 item.second.get_ptr<const std::string*>();
521 if (value == nullptr)
522 {
523 messages::propertyValueFormatError(
524 asyncResp->res, item.second,
525 "HttpHeaders/" + item.first);
526 return;
527 }
528 // Adding a new json value is the size of the key, +
529 // the size of the value + 2 * 2 quotes for each, +
530 // the colon and space between. example:
531 // "key": "value"
532 cumulativeLen += item.first.size() + value->size() + 6;
533 // This value is selected to mirror http_connection.hpp
534 constexpr const uint16_t maxHeaderSizeED = 8096;
535 if (cumulativeLen > maxHeaderSizeED)
536 {
537 messages::arraySizeTooLong(
538 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
539 return;
540 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700541 subValue->userSub.httpHeaders.set(item.first, *value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400542 }
543 }
544 }
545
546 if (regPrefixes)
547 {
548 for (const std::string& it : *regPrefixes)
549 {
550 if (std::ranges::find(supportedRegPrefixes, it) ==
551 supportedRegPrefixes.end())
552 {
553 messages::propertyValueNotInList(asyncResp->res, it,
554 "RegistryPrefixes");
555 return;
556 }
557 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700558 subValue->userSub.registryPrefixes = *regPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400559 }
560
Ed Tanousa14c9112024-09-04 10:46:47 -0700561 if (originResources)
562 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700563 subValue->userSub.originResources = *originResources;
Ed Tanousa14c9112024-09-04 10:46:47 -0700564 }
565
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400566 if (resTypes)
567 {
568 for (const std::string& it : *resTypes)
569 {
570 if (std::ranges::find(supportedResourceTypes, it) ==
571 supportedResourceTypes.end())
572 {
573 messages::propertyValueNotInList(asyncResp->res, it,
574 "ResourceTypes");
575 return;
576 }
577 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700578 subValue->userSub.resourceTypes = *resTypes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400579 }
580
581 if (msgIds)
582 {
583 std::vector<std::string> registryPrefix;
584
585 // If no registry prefixes are mentioned, consider all
586 // supported prefixes
Ed Tanous4b712a22023-08-02 12:56:52 -0700587 if (subValue->userSub.registryPrefixes.empty())
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400588 {
589 registryPrefix.assign(supportedRegPrefixes.begin(),
590 supportedRegPrefixes.end());
591 }
592 else
593 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700594 registryPrefix = subValue->userSub.registryPrefixes;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400595 }
596
597 for (const std::string& id : *msgIds)
598 {
599 bool validId = false;
600
601 // Check for Message ID in each of the selected Registry
602 for (const std::string& it : registryPrefix)
603 {
604 const std::span<const redfish::registries::MessageEntry>
605 registry =
606 redfish::registries::getRegistryFromPrefix(it);
607
608 if (std::ranges::any_of(
609 registry,
610 [&id](const redfish::registries::MessageEntry&
611 messageEntry) {
612 return id == messageEntry.first;
613 }))
614 {
615 validId = true;
616 break;
617 }
618 }
619
620 if (!validId)
621 {
622 messages::propertyValueNotInList(asyncResp->res, id,
623 "MessageIds");
624 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 }
626 }
627
Ed Tanous4b712a22023-08-02 12:56:52 -0700628 subValue->userSub.registryMsgIds = *msgIds;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400629 }
630
631 if (retryPolicy)
632 {
633 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
634 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700635 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400636 messages::propertyValueNotInList(
637 asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800638 return;
639 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700640 subValue->userSub.retryPolicy = *retryPolicy;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400641 }
642 else
643 {
644 // Default "TerminateAfterRetries"
Ed Tanous4b712a22023-08-02 12:56:52 -0700645 subValue->userSub.retryPolicy = "TerminateAfterRetries";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400646 }
647
648 if (mrdJsonArray)
649 {
650 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
651 {
652 std::string mrdUri;
653
654 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
655 "@odata.id", mrdUri))
656
657 {
658 return;
659 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700660 subValue->userSub.metricReportDefinitions.emplace_back(
661 mrdUri);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400662 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800663 }
664
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400665 std::string id =
666 EventServiceManager::getInstance().addPushSubscription(
667 subValue);
668 if (id.empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800669 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400670 messages::internalError(asyncResp->res);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800671 return;
672 }
673
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400674 messages::created(asyncResp->res);
675 asyncResp->res.addHeader(
676 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
677 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700678}
679
680inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530681{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500682 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700683 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700684 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700685 [&app](const crow::Request& req,
686 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
687 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400688 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
689 {
690 return;
691 }
Chicago Duan3d307082020-11-26 14:12:12 +0800692
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400693 if (param.starts_with("snmp"))
694 {
695 getSnmpTrapClient(asyncResp, param);
696 return;
697 }
Chicago Duan3d307082020-11-26 14:12:12 +0800698
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400699 std::shared_ptr<Subscription> subValue =
700 EventServiceManager::getInstance().getSubscription(param);
701 if (subValue == nullptr)
702 {
703 asyncResp->res.result(
704 boost::beast::http::status::not_found);
705 return;
706 }
707 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530708
Ed Tanous4b712a22023-08-02 12:56:52 -0700709 const persistent_data::UserSubscription& userSub =
710 subValue->userSub;
zhanghch058d1b46d2021-04-01 11:18:24 +0800711
Ed Tanous4b712a22023-08-02 12:56:52 -0700712 nlohmann::json& jVal = asyncResp->res.jsonValue;
713 jVal["@odata.type"] =
714 "#EventDestination.v1_14_1.EventDestination";
715 jVal["Protocol"] =
716 event_destination::EventDestinationProtocol::Redfish;
717 jVal["@odata.id"] = boost::urls::format(
718 "/redfish/v1/EventService/Subscriptions/{}", id);
719 jVal["Id"] = id;
720 jVal["Name"] = "Event Destination " + id;
721 jVal["Destination"] = userSub.destinationUrl;
722 jVal["Context"] = userSub.customText;
723 jVal["SubscriptionType"] = userSub.subscriptionType;
724 jVal["HttpHeaders"] = nlohmann::json::array();
725 jVal["EventFormatType"] = userSub.eventFormatType;
726 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
727 jVal["ResourceTypes"] = userSub.resourceTypes;
728
729 jVal["MessageIds"] = userSub.registryMsgIds;
730 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
731 jVal["VerifyCertificate"] = userSub.verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530732
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400733 nlohmann::json::array_t mrdJsonArray;
Ed Tanous4b712a22023-08-02 12:56:52 -0700734 for (const auto& mdrUri : userSub.metricReportDefinitions)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400735 {
736 nlohmann::json::object_t mdr;
737 mdr["@odata.id"] = mdrUri;
738 mrdJsonArray.emplace_back(std::move(mdr));
739 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700740 jVal["MetricReportDefinitions"] = mrdJsonArray;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400741 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500742 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700743 // The below privilege is wrong, it should be ConfigureManager OR
744 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500745 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700746 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700747 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700748 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700749 [&app](const crow::Request& req,
750 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
751 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400752 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700753 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400754 return;
755 }
756 std::shared_ptr<Subscription> subValue =
757 EventServiceManager::getInstance().getSubscription(param);
758 if (subValue == nullptr)
759 {
760 asyncResp->res.result(
761 boost::beast::http::status::not_found);
762 return;
763 }
764
765 std::optional<std::string> context;
766 std::optional<std::string> retryPolicy;
767 std::optional<bool> verifyCertificate;
768 std::optional<std::vector<nlohmann::json::object_t>> headers;
769
Myung Baeafc474a2024-10-09 00:53:29 -0700770 if (!json_util::readJsonPatch( //
771 req, asyncResp->res, //
772 "Context", context, //
773 "DeliveryRetryPolicy", retryPolicy, //
774 "HttpHeaders", headers, //
775 "VerifyCertificate", verifyCertificate //
776 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400777 {
778 return;
779 }
780
781 if (context)
782 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700783 subValue->userSub.customText = *context;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400784 }
785
786 if (headers)
787 {
788 boost::beast::http::fields fields;
789 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700790 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400791 for (const auto& it : headerChunk)
792 {
793 const std::string* value =
794 it.second.get_ptr<const std::string*>();
795 if (value == nullptr)
796 {
797 messages::propertyValueFormatError(
798 asyncResp->res, it.second,
799 "HttpHeaders/" + it.first);
800 return;
801 }
802 fields.set(it.first, *value);
803 }
804 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700805 subValue->userSub.httpHeaders = std::move(fields);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400806 }
807
808 if (retryPolicy)
809 {
810 if (std::ranges::find(supportedRetryPolicies,
811 *retryPolicy) ==
812 supportedRetryPolicies.end())
813 {
814 messages::propertyValueNotInList(asyncResp->res,
815 *retryPolicy,
816 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700817 return;
818 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700819 subValue->userSub.retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700820 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530821
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400822 if (verifyCertificate)
823 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700824 subValue->userSub.verifyCertificate = *verifyCertificate;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400825 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700826
Myung Bae56ba3862024-10-10 17:09:37 -0700827 // Sync Subscription to UserSubscriptionConfig
828 persistent_data::EventServiceStore::getInstance()
829 .updateUserSubscriptionConfig(subValue->userSub);
830
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400831 EventServiceManager::getInstance().updateSubscriptionData();
832 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500833 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700834 // The below privilege is wrong, it should be ConfigureManager OR
835 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500836 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700837 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700838 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700839 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700840 [&app](const crow::Request& req,
841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
842 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400843 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
844 {
845 return;
846 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700847 EventServiceManager& event = EventServiceManager::getInstance();
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400848 if (param.starts_with("snmp"))
849 {
850 deleteSnmpTrapClient(asyncResp, param);
Ed Tanous4b712a22023-08-02 12:56:52 -0700851 event.deleteSubscription(param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400852 return;
853 }
Chicago Duan3d307082020-11-26 14:12:12 +0800854
Ed Tanous4b712a22023-08-02 12:56:52 -0700855 if (!event.deleteSubscription(param))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400856 {
Ed Tanous4b712a22023-08-02 12:56:52 -0700857 messages::resourceNotFound(asyncResp->res,
858 "EventDestination", param);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400859 return;
860 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700861 messages::success(asyncResp->res);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400862 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700863}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530864
865} // namespace redfish