blob: ff3de8298a0efabe1e120b017cc83cc7323b19bf [file] [log] [blame]
AppaRao Pulie5aaf042020-03-20 01:05:52 +05301/*
2// Copyright (c) 2020 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
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>
Patrick Williams1e270c52021-12-04 06:06:56 -060037
AppaRao Pulie5aaf042020-03-20 01:05:52 +053038namespace redfish
39{
40
AppaRao Puli156d6b02020-04-25 06:04:05 +053041static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
42 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053043static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053044 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053045static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
46 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
47
Sunitha Harishe56f2542020-07-22 02:38:59 -050048static constexpr const std::array<const char*, 1> supportedResourceTypes = {
49 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050050
John Edward Broadbent7e860f12021-04-08 15:57:16 -070051inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053052{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070053 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070054 .privileges(redfish::privileges::getEventService)
Patrick Williamsbd79bce2024-08-16 15:22:20 -040055 .methods(
56 boost::beast::http::verb::
57 get)([&app](
58 const crow::Request& req,
59 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
60 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
61 {
62 return;
63 }
Ed Tanous14766872022-03-15 10:44:42 -070064
Patrick Williamsbd79bce2024-08-16 15:22:20 -040065 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
66 asyncResp->res.jsonValue["@odata.type"] =
67 "#EventService.v1_5_0.EventService";
68 asyncResp->res.jsonValue["Id"] = "EventService";
69 asyncResp->res.jsonValue["Name"] = "Event Service";
70 asyncResp->res.jsonValue["ServerSentEventUri"] =
71 "/redfish/v1/EventService/SSE";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000072
Patrick Williamsbd79bce2024-08-16 15:22:20 -040073 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
74 "/redfish/v1/EventService/Subscriptions";
75 asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
76 ["target"] =
77 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053078
Patrick Williamsbd79bce2024-08-16 15:22:20 -040079 const persistent_data::EventServiceConfig eventServiceConfig =
80 persistent_data::EventServiceStore::getInstance()
81 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080082
Patrick Williamsbd79bce2024-08-16 15:22:20 -040083 asyncResp->res.jsonValue["Status"]["State"] =
84 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
85 asyncResp->res.jsonValue["ServiceEnabled"] =
86 eventServiceConfig.enabled;
87 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
88 eventServiceConfig.retryAttempts;
89 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
90 eventServiceConfig.retryTimeoutInterval;
91 asyncResp->res.jsonValue["EventFormatTypes"] =
92 supportedEvtFormatTypes;
93 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
94 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053095
Patrick Williamsbd79bce2024-08-16 15:22:20 -040096 nlohmann::json::object_t supportedSSEFilters;
97 supportedSSEFilters["EventFormatType"] = true;
98 supportedSSEFilters["MessageId"] = true;
99 supportedSSEFilters["MetricReportDefinition"] = true;
100 supportedSSEFilters["RegistryPrefix"] = true;
101 supportedSSEFilters["OriginResource"] = false;
102 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530103
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400104 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
105 std::move(supportedSSEFilters);
106 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530107
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700108 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700109 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700110 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700111 [&app](const crow::Request& req,
112 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400113 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114 {
115 return;
116 }
117 std::optional<bool> serviceEnabled;
118 std::optional<uint32_t> retryAttemps;
119 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530120
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400121 if (!json_util::readJsonPatch(
122 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
123 "DeliveryRetryAttempts", retryAttemps,
124 "DeliveryRetryIntervalSeconds", retryInterval))
125 {
126 return;
127 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530128
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400129 persistent_data::EventServiceConfig eventServiceConfig =
130 persistent_data::EventServiceStore::getInstance()
131 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700132
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400133 if (serviceEnabled)
134 {
135 eventServiceConfig.enabled = *serviceEnabled;
136 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500137
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400138 if (retryAttemps)
139 {
140 // Supported range [1-3]
141 if ((*retryAttemps < 1) || (*retryAttemps > 3))
142 {
143 messages::queryParameterOutOfRange(
144 asyncResp->res, std::to_string(*retryAttemps),
145 "DeliveryRetryAttempts", "[1-3]");
146 }
147 else
148 {
149 eventServiceConfig.retryAttempts = *retryAttemps;
150 }
151 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530152
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400153 if (retryInterval)
154 {
155 // Supported range [5 - 180]
156 if ((*retryInterval < 5) || (*retryInterval > 180))
157 {
158 messages::queryParameterOutOfRange(
159 asyncResp->res, std::to_string(*retryInterval),
160 "DeliveryRetryIntervalSeconds", "[5-180]");
161 }
162 else
163 {
164 eventServiceConfig.retryTimeoutInterval =
165 *retryInterval;
166 }
167 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700168
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400169 EventServiceManager::getInstance().setEventServiceConfig(
170 eventServiceConfig);
171 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700172}
173
174inline void requestRoutesSubmitTestEvent(App& app)
175{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700176 BMCWEB_ROUTE(
177 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700178 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700179 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700180 [&app](const crow::Request& req,
181 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400182 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
183 {
184 return;
185 }
186 if (!EventServiceManager::getInstance().sendTestEventLog())
187 {
188 messages::serviceDisabled(asyncResp->res,
189 "/redfish/v1/EventService/");
190 return;
191 }
192 asyncResp->res.result(boost::beast::http::status::no_content);
193 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700194}
195
Chicago Duan3d307082020-11-26 14:12:12 +0800196inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700197 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800198 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
199 const dbus::utility::ManagedObjectType& resp)
200{
201 if (ec)
202 {
Ed Tanous13061012023-07-25 11:12:19 -0700203 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800204 {
205 // This is an optional process so just return if it isn't there
206 return;
207 }
208
Ed Tanous62598e32023-07-17 17:06:25 -0700209 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800210 messages::internalError(asyncResp->res);
211 return;
212 }
213 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
214 for (const auto& objpath : resp)
215 {
216 sdbusplus::message::object_path path(objpath.first);
217 const std::string snmpId = path.filename();
218 if (snmpId.empty())
219 {
Ed Tanous62598e32023-07-17 17:06:25 -0700220 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800221 messages::internalError(asyncResp->res);
222 return;
223 }
224
225 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
226 }
227}
228
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700229inline void requestRoutesEventDestinationCollection(App& app)
230{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000231 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700232 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700233 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700234 [&app](const crow::Request& req,
235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400236 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
237 {
238 return;
239 }
240 asyncResp->res.jsonValue["@odata.type"] =
241 "#EventDestinationCollection.EventDestinationCollection";
242 asyncResp->res.jsonValue["@odata.id"] =
243 "/redfish/v1/EventService/Subscriptions";
244 asyncResp->res.jsonValue["Name"] =
245 "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700246
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400247 nlohmann::json& memberArray =
248 asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700249
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400250 std::vector<std::string> subscripIds =
251 EventServiceManager::getInstance().getAllIDs();
252 memberArray = nlohmann::json::array();
253 asyncResp->res.jsonValue["Members@odata.count"] =
254 subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700255
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400256 for (const std::string& id : subscripIds)
257 {
258 nlohmann::json::object_t member;
259 member["@odata.id"] = boost::urls::format(
260 "/redfish/v1/EventService/Subscriptions/{}" + id);
261 memberArray.emplace_back(std::move(member));
262 }
263 crow::connections::systemBus->async_method_call(
264 [asyncResp](const boost::system::error_code& ec,
265 const dbus::utility::ManagedObjectType& resp) {
266 doSubscriptionCollection(ec, asyncResp, resp);
267 },
268 "xyz.openbmc_project.Network.SNMP",
269 "/xyz/openbmc_project/network/snmp/manager",
270 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
271 });
Chicago Duan3d307082020-11-26 14:12:12 +0800272
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700273 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500274 .privileges(redfish::privileges::postEventDestinationCollection)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400275 .methods(
276 boost::beast::http::verb::
277 post)([&app](
278 const crow::Request& req,
279 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
280 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
281 {
282 return;
283 }
284 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
285 maxNoOfSubscriptions)
286 {
287 messages::eventSubscriptionLimitExceeded(asyncResp->res);
288 return;
289 }
290 std::string destUrl;
291 std::string protocol;
292 std::optional<bool> verifyCertificate;
293 std::optional<std::string> context;
294 std::optional<std::string> subscriptionType;
295 std::optional<std::string> eventFormatType2;
296 std::optional<std::string> retryPolicy;
297 std::optional<std::vector<std::string>> msgIds;
298 std::optional<std::vector<std::string>> regPrefixes;
299 std::optional<std::vector<std::string>> resTypes;
300 std::optional<std::vector<nlohmann::json::object_t>> headers;
301 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800302
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400303 if (!json_util::readJsonPatch(
304 req, asyncResp->res, "Destination", destUrl, "Context",
305 context, "Protocol", protocol, "SubscriptionType",
306 subscriptionType, "EventFormatType", eventFormatType2,
307 "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
308 "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
309 "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
310 resTypes, "VerifyCertificate", verifyCertificate))
Ed Tanousfffb8c12022-02-07 23:53:03 -0800311 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700312 return;
313 }
Chicago Duan3d307082020-11-26 14:12:12 +0800314
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400315 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
316 static constexpr const uint16_t maxDestinationSize = 2000;
317 if (destUrl.size() > maxDestinationSize)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800318 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400319 messages::stringValueTooLong(asyncResp->res, "Destination",
320 maxDestinationSize);
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 return;
322 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700323
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400324 if (regPrefixes && msgIds)
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400326 if (!regPrefixes->empty() && !msgIds->empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700327 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400328 messages::propertyValueConflict(
329 asyncResp->res, "MessageIds", "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530330 return;
331 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800332 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530333
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400334 boost::system::result<boost::urls::url> url =
335 boost::urls::parse_absolute_uri(destUrl);
336 if (!url)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800337 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400338 BMCWEB_LOG_WARNING(
339 "Failed to validate and split destination url");
340 messages::propertyValueFormatError(asyncResp->res, destUrl,
341 "Destination");
342 return;
343 }
344 url->normalize();
345 crow::utility::setProtocolDefaults(*url, protocol);
346 crow::utility::setPortDefaults(*url);
347
348 if (url->path().empty())
349 {
350 url->set_path("/");
351 }
352
353 if (url->has_userinfo())
354 {
355 messages::propertyValueFormatError(asyncResp->res, destUrl,
356 "Destination");
357 return;
358 }
359
360 if (protocol == "SNMPv2c")
361 {
362 if (context)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700363 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400364 messages::propertyValueConflict(asyncResp->res, "Context",
365 "Protocol");
AppaRao Puli144b6312020-08-03 22:23:12 +0530366 return;
367 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400368 if (eventFormatType2)
369 {
370 messages::propertyValueConflict(
371 asyncResp->res, "EventFormatType", "Protocol");
372 return;
373 }
374 if (retryPolicy)
375 {
376 messages::propertyValueConflict(asyncResp->res,
377 "RetryPolicy", "Protocol");
378 return;
379 }
380 if (msgIds)
381 {
382 messages::propertyValueConflict(asyncResp->res,
383 "MessageIds", "Protocol");
384 return;
385 }
386 if (regPrefixes)
387 {
388 messages::propertyValueConflict(
389 asyncResp->res, "RegistryPrefixes", "Protocol");
390 return;
391 }
392 if (resTypes)
393 {
394 messages::propertyValueConflict(
395 asyncResp->res, "ResourceTypes", "Protocol");
396 return;
397 }
398 if (headers)
399 {
400 messages::propertyValueConflict(asyncResp->res,
401 "HttpHeaders", "Protocol");
402 return;
403 }
404 if (mrdJsonArray)
405 {
406 messages::propertyValueConflict(
407 asyncResp->res, "MetricReportDefinitions", "Protocol");
408 return;
409 }
410 if (url->scheme() != "snmp")
411 {
412 messages::propertyValueConflict(asyncResp->res,
413 "Destination", "Protocol");
414 return;
415 }
416
417 addSnmpTrapClient(asyncResp, url->host_address(),
418 url->port_number());
419 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700421
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400422 std::shared_ptr<Subscription> subValue =
423 std::make_shared<Subscription>(*url, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700424
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400425 subValue->destinationUrl = std::move(*url);
426
427 if (subscriptionType)
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400429 if (*subscriptionType != "RedfishEvent")
430 {
431 messages::propertyValueNotInList(
432 asyncResp->res, *subscriptionType, "SubscriptionType");
433 return;
434 }
435 subValue->subscriptionType = *subscriptionType;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800436 }
437 else
438 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400439 subValue->subscriptionType = "RedfishEvent"; // Default
Ed Tanousfffb8c12022-02-07 23:53:03 -0800440 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530441
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400442 if (protocol != "Redfish")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800443 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400444 messages::propertyValueNotInList(asyncResp->res, protocol,
445 "Protocol");
446 return;
447 }
448 subValue->protocol = protocol;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800449
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400450 if (verifyCertificate)
451 {
452 subValue->verifyCertificate = *verifyCertificate;
453 }
454
455 if (eventFormatType2)
456 {
457 if (std::ranges::find(supportedEvtFormatTypes,
458 *eventFormatType2) ==
459 supportedEvtFormatTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700460 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400461 messages::propertyValueNotInList(
462 asyncResp->res, *eventFormatType2, "EventFormatType");
463 return;
464 }
465 subValue->eventFormatType = *eventFormatType2;
466 }
467 else
468 {
469 // If not specified, use default "Event"
470 subValue->eventFormatType = "Event";
471 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700472
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400473 if (context)
474 {
475 // This value is selected arbitrarily.
476 constexpr const size_t maxContextSize = 256;
477 if (context->size() > maxContextSize)
478 {
479 messages::stringValueTooLong(asyncResp->res, "Context",
480 maxContextSize);
481 return;
482 }
483 subValue->customText = *context;
484 }
485
486 if (headers)
487 {
488 size_t cumulativeLen = 0;
489
490 for (const nlohmann::json::object_t& headerChunk : *headers)
491 {
492 for (const auto& item : headerChunk)
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400494 const std::string* value =
495 item.second.get_ptr<const std::string*>();
496 if (value == nullptr)
497 {
498 messages::propertyValueFormatError(
499 asyncResp->res, item.second,
500 "HttpHeaders/" + item.first);
501 return;
502 }
503 // Adding a new json value is the size of the key, +
504 // the size of the value + 2 * 2 quotes for each, +
505 // the colon and space between. example:
506 // "key": "value"
507 cumulativeLen += item.first.size() + value->size() + 6;
508 // This value is selected to mirror http_connection.hpp
509 constexpr const uint16_t maxHeaderSizeED = 8096;
510 if (cumulativeLen > maxHeaderSizeED)
511 {
512 messages::arraySizeTooLong(
513 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
514 return;
515 }
516 subValue->httpHeaders.set(item.first, *value);
517 }
518 }
519 }
520
521 if (regPrefixes)
522 {
523 for (const std::string& it : *regPrefixes)
524 {
525 if (std::ranges::find(supportedRegPrefixes, it) ==
526 supportedRegPrefixes.end())
527 {
528 messages::propertyValueNotInList(asyncResp->res, it,
529 "RegistryPrefixes");
530 return;
531 }
532 }
533 subValue->registryPrefixes = *regPrefixes;
534 }
535
536 if (resTypes)
537 {
538 for (const std::string& it : *resTypes)
539 {
540 if (std::ranges::find(supportedResourceTypes, it) ==
541 supportedResourceTypes.end())
542 {
543 messages::propertyValueNotInList(asyncResp->res, it,
544 "ResourceTypes");
545 return;
546 }
547 }
548 subValue->resourceTypes = *resTypes;
549 }
550
551 if (msgIds)
552 {
553 std::vector<std::string> registryPrefix;
554
555 // If no registry prefixes are mentioned, consider all
556 // supported prefixes
557 if (subValue->registryPrefixes.empty())
558 {
559 registryPrefix.assign(supportedRegPrefixes.begin(),
560 supportedRegPrefixes.end());
561 }
562 else
563 {
564 registryPrefix = subValue->registryPrefixes;
565 }
566
567 for (const std::string& id : *msgIds)
568 {
569 bool validId = false;
570
571 // Check for Message ID in each of the selected Registry
572 for (const std::string& it : registryPrefix)
573 {
574 const std::span<const redfish::registries::MessageEntry>
575 registry =
576 redfish::registries::getRegistryFromPrefix(it);
577
578 if (std::ranges::any_of(
579 registry,
580 [&id](const redfish::registries::MessageEntry&
581 messageEntry) {
582 return id == messageEntry.first;
583 }))
584 {
585 validId = true;
586 break;
587 }
588 }
589
590 if (!validId)
591 {
592 messages::propertyValueNotInList(asyncResp->res, id,
593 "MessageIds");
594 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700595 }
596 }
597
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400598 subValue->registryMsgIds = *msgIds;
599 }
600
601 if (retryPolicy)
602 {
603 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
604 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400606 messages::propertyValueNotInList(
607 asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800608 return;
609 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400610 subValue->retryPolicy = *retryPolicy;
611 }
612 else
613 {
614 // Default "TerminateAfterRetries"
615 subValue->retryPolicy = "TerminateAfterRetries";
616 }
617
618 if (mrdJsonArray)
619 {
620 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
621 {
622 std::string mrdUri;
623
624 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
625 "@odata.id", mrdUri))
626
627 {
628 return;
629 }
630 subValue->metricReportDefinitions.emplace_back(mrdUri);
631 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800632 }
633
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400634 std::string id =
635 EventServiceManager::getInstance().addPushSubscription(
636 subValue);
637 if (id.empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800638 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400639 messages::internalError(asyncResp->res);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800640 return;
641 }
642
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400643 messages::created(asyncResp->res);
644 asyncResp->res.addHeader(
645 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
646 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700647}
648
649inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530650{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500651 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700652 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700653 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700654 [&app](const crow::Request& req,
655 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
656 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400657 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
658 {
659 return;
660 }
Chicago Duan3d307082020-11-26 14:12:12 +0800661
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400662 if (param.starts_with("snmp"))
663 {
664 getSnmpTrapClient(asyncResp, param);
665 return;
666 }
Chicago Duan3d307082020-11-26 14:12:12 +0800667
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400668 std::shared_ptr<Subscription> subValue =
669 EventServiceManager::getInstance().getSubscription(param);
670 if (subValue == nullptr)
671 {
672 asyncResp->res.result(
673 boost::beast::http::status::not_found);
674 return;
675 }
676 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530677
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400678 asyncResp->res.jsonValue["@odata.type"] =
679 "#EventDestination.v1_8_0.EventDestination";
680 asyncResp->res.jsonValue["Protocol"] =
681 event_destination::EventDestinationProtocol::Redfish;
682 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
683 "/redfish/v1/EventService/Subscriptions/{}", id);
684 asyncResp->res.jsonValue["Id"] = id;
685 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
686 asyncResp->res.jsonValue["Destination"] =
687 subValue->destinationUrl;
688 asyncResp->res.jsonValue["Context"] = subValue->customText;
689 asyncResp->res.jsonValue["SubscriptionType"] =
690 subValue->subscriptionType;
691 asyncResp->res.jsonValue["HttpHeaders"] =
692 nlohmann::json::array();
693 asyncResp->res.jsonValue["EventFormatType"] =
694 subValue->eventFormatType;
695 asyncResp->res.jsonValue["RegistryPrefixes"] =
696 subValue->registryPrefixes;
697 asyncResp->res.jsonValue["ResourceTypes"] =
698 subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800699
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400700 asyncResp->res.jsonValue["MessageIds"] =
701 subValue->registryMsgIds;
702 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
703 subValue->retryPolicy;
704 asyncResp->res.jsonValue["VerifyCertificate"] =
705 subValue->verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530706
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400707 nlohmann::json::array_t mrdJsonArray;
708 for (const auto& mdrUri : subValue->metricReportDefinitions)
709 {
710 nlohmann::json::object_t mdr;
711 mdr["@odata.id"] = mdrUri;
712 mrdJsonArray.emplace_back(std::move(mdr));
713 }
714 asyncResp->res.jsonValue["MetricReportDefinitions"] =
715 mrdJsonArray;
716 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500717 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700718 // The below privilege is wrong, it should be ConfigureManager OR
719 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500720 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700721 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700722 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700723 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700724 [&app](const crow::Request& req,
725 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
726 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400727 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700728 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400729 return;
730 }
731 std::shared_ptr<Subscription> subValue =
732 EventServiceManager::getInstance().getSubscription(param);
733 if (subValue == nullptr)
734 {
735 asyncResp->res.result(
736 boost::beast::http::status::not_found);
737 return;
738 }
739
740 std::optional<std::string> context;
741 std::optional<std::string> retryPolicy;
742 std::optional<bool> verifyCertificate;
743 std::optional<std::vector<nlohmann::json::object_t>> headers;
744
745 if (!json_util::readJsonPatch(
746 req, asyncResp->res, "Context", context,
747 "VerifyCertificate", verifyCertificate,
748 "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
749 headers))
750 {
751 return;
752 }
753
754 if (context)
755 {
756 subValue->customText = *context;
757 }
758
759 if (headers)
760 {
761 boost::beast::http::fields fields;
762 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous601c71a2021-09-08 16:40:12 -0700763 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400764 for (const auto& it : headerChunk)
765 {
766 const std::string* value =
767 it.second.get_ptr<const std::string*>();
768 if (value == nullptr)
769 {
770 messages::propertyValueFormatError(
771 asyncResp->res, it.second,
772 "HttpHeaders/" + it.first);
773 return;
774 }
775 fields.set(it.first, *value);
776 }
777 }
778 subValue->httpHeaders = std::move(fields);
779 }
780
781 if (retryPolicy)
782 {
783 if (std::ranges::find(supportedRetryPolicies,
784 *retryPolicy) ==
785 supportedRetryPolicies.end())
786 {
787 messages::propertyValueNotInList(asyncResp->res,
788 *retryPolicy,
789 "DeliveryRetryPolicy");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700790 return;
791 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400792 subValue->retryPolicy = *retryPolicy;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700793 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530794
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400795 if (verifyCertificate)
796 {
797 subValue->verifyCertificate = *verifyCertificate;
798 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700799
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400800 EventServiceManager::getInstance().updateSubscriptionData();
801 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500802 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700803 // The below privilege is wrong, it should be ConfigureManager OR
804 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500805 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700806 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700807 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700808 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700809 [&app](const crow::Request& req,
810 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
811 const std::string& param) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400812 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
813 {
814 return;
815 }
Chicago Duan3d307082020-11-26 14:12:12 +0800816
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400817 if (param.starts_with("snmp"))
818 {
819 deleteSnmpTrapClient(asyncResp, param);
820 EventServiceManager::getInstance().deleteSubscription(
821 param);
822 return;
823 }
Chicago Duan3d307082020-11-26 14:12:12 +0800824
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400825 if (!EventServiceManager::getInstance().isSubscriptionExist(
826 param))
827 {
828 asyncResp->res.result(
829 boost::beast::http::status::not_found);
830 return;
831 }
832 EventServiceManager::getInstance().deleteSubscription(param);
833 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700834}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530835
836} // namespace redfish