blob: aa88b0958b03d3b3a4c6e94bc27531318bd0a047 [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>
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"] =
Myung Bae87599612024-09-11 10:11:34 -0400679 "#EventDestination.v1_14_1.EventDestination";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400680 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