blob: b49e35afe11896ac5603c755f766f28672ef3773 [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 Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "http/utility.hpp"
20#include "logging.hpp"
21#include "query.hpp"
22#include "registries/privilege_registry.hpp"
Chicago Duan3d307082020-11-26 14:12:12 +080023#include "snmp_trap_event_clients.hpp"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053024
Ed Tanous601c71a2021-09-08 16:40:12 -070025#include <boost/beast/http/fields.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080026#include <boost/system/error_code.hpp>
27#include <sdbusplus/unpack_properties.hpp>
28#include <utils/dbus_utils.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070029
Chicago Duan3d307082020-11-26 14:12:12 +080030#include <charconv>
31#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070032#include <ranges>
Patrick Williams1e270c52021-12-04 06:06:56 -060033#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080034#include <string>
Patrick Williams1e270c52021-12-04 06:06:56 -060035
AppaRao Pulie5aaf042020-03-20 01:05:52 +053036namespace redfish
37{
38
AppaRao Puli156d6b02020-04-25 06:04:05 +053039static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
40 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053041static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053042 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053043static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
44 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
45
Sunitha Harishe56f2542020-07-22 02:38:59 -050046static constexpr const std::array<const char*, 1> supportedResourceTypes = {
47 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050048
John Edward Broadbent7e860f12021-04-08 15:57:16 -070049inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053050{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070051 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070052 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070053 .methods(boost::beast::http::verb::get)(
54 [&app](const crow::Request& req,
55 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000056 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070057 {
58 return;
59 }
Ed Tanous14766872022-03-15 10:44:42 -070060
Ed Tanous002d39b2022-05-31 08:59:27 -070061 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
62 asyncResp->res.jsonValue["@odata.type"] =
63 "#EventService.v1_5_0.EventService";
64 asyncResp->res.jsonValue["Id"] = "EventService";
65 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000066 asyncResp->res.jsonValue["ServerSentEventUri"] =
67 "/redfish/v1/EventService/SSE";
68
Ed Tanous002d39b2022-05-31 08:59:27 -070069 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
70 "/redfish/v1/EventService/Subscriptions";
71 asyncResp->res
72 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
73 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053074
Ed Tanous002d39b2022-05-31 08:59:27 -070075 const persistent_data::EventServiceConfig eventServiceConfig =
76 persistent_data::EventServiceStore::getInstance()
77 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080078
Ed Tanous002d39b2022-05-31 08:59:27 -070079 asyncResp->res.jsonValue["Status"]["State"] =
80 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
81 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
82 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
83 eventServiceConfig.retryAttempts;
84 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
85 eventServiceConfig.retryTimeoutInterval;
86 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
87 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
88 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053089
Ed Tanous613dabe2022-07-09 11:17:36 -070090 nlohmann::json::object_t supportedSSEFilters;
91 supportedSSEFilters["EventFormatType"] = true;
92 supportedSSEFilters["MessageId"] = true;
93 supportedSSEFilters["MetricReportDefinition"] = true;
94 supportedSSEFilters["RegistryPrefix"] = true;
95 supportedSSEFilters["OriginResource"] = false;
96 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053097
Ed Tanous002d39b2022-05-31 08:59:27 -070098 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -070099 std::move(supportedSSEFilters);
George Liu0fda0f12021-11-16 10:06:17 +0800100 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530101
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700102 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700103 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700104 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700105 [&app](const crow::Request& req,
106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000107 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700108 {
109 return;
110 }
111 std::optional<bool> serviceEnabled;
112 std::optional<uint32_t> retryAttemps;
113 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530114
Ed Tanous002d39b2022-05-31 08:59:27 -0700115 if (!json_util::readJsonPatch(
116 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
117 "DeliveryRetryAttempts", retryAttemps,
118 "DeliveryRetryIntervalSeconds", retryInterval))
119 {
120 return;
121 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530122
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 persistent_data::EventServiceConfig eventServiceConfig =
124 persistent_data::EventServiceStore::getInstance()
125 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700126
Ed Tanous002d39b2022-05-31 08:59:27 -0700127 if (serviceEnabled)
128 {
129 eventServiceConfig.enabled = *serviceEnabled;
130 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500131
Ed Tanous002d39b2022-05-31 08:59:27 -0700132 if (retryAttemps)
133 {
134 // Supported range [1-3]
135 if ((*retryAttemps < 1) || (*retryAttemps > 3))
136 {
137 messages::queryParameterOutOfRange(
138 asyncResp->res, std::to_string(*retryAttemps),
139 "DeliveryRetryAttempts", "[1-3]");
140 }
141 else
142 {
143 eventServiceConfig.retryAttempts = *retryAttemps;
144 }
145 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530146
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 if (retryInterval)
148 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600149 // Supported range [5 - 180]
150 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 {
152 messages::queryParameterOutOfRange(
153 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600154 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 }
156 else
157 {
158 eventServiceConfig.retryTimeoutInterval = *retryInterval;
159 }
160 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700161
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 EventServiceManager::getInstance().setEventServiceConfig(
163 eventServiceConfig);
164 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165}
166
167inline void requestRoutesSubmitTestEvent(App& app)
168{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169 BMCWEB_ROUTE(
170 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700171 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700172 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700173 [&app](const crow::Request& req,
174 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000175 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700176 {
177 return;
178 }
179 if (!EventServiceManager::getInstance().sendTestEventLog())
180 {
181 messages::serviceDisabled(asyncResp->res,
182 "/redfish/v1/EventService/");
183 return;
184 }
185 asyncResp->res.result(boost::beast::http::status::no_content);
186 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700187}
188
Chicago Duan3d307082020-11-26 14:12:12 +0800189inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700190 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
192 const dbus::utility::ManagedObjectType& resp)
193{
194 if (ec)
195 {
Ed Tanous13061012023-07-25 11:12:19 -0700196 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800197 {
198 // This is an optional process so just return if it isn't there
199 return;
200 }
201
Ed Tanous62598e32023-07-17 17:06:25 -0700202 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800203 messages::internalError(asyncResp->res);
204 return;
205 }
206 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
207 for (const auto& objpath : resp)
208 {
209 sdbusplus::message::object_path path(objpath.first);
210 const std::string snmpId = path.filename();
211 if (snmpId.empty())
212 {
Ed Tanous62598e32023-07-17 17:06:25 -0700213 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800214 messages::internalError(asyncResp->res);
215 return;
216 }
217
218 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
219 }
220}
221
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700222inline void requestRoutesEventDestinationCollection(App& app)
223{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000224 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700225 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700226 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700227 [&app](const crow::Request& req,
228 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000229 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700230 {
231 return;
232 }
233 asyncResp->res.jsonValue["@odata.type"] =
234 "#EventDestinationCollection.EventDestinationCollection";
235 asyncResp->res.jsonValue["@odata.id"] =
236 "/redfish/v1/EventService/Subscriptions";
237 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700238
Ed Tanous002d39b2022-05-31 08:59:27 -0700239 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700240
Ed Tanous002d39b2022-05-31 08:59:27 -0700241 std::vector<std::string> subscripIds =
242 EventServiceManager::getInstance().getAllIDs();
243 memberArray = nlohmann::json::array();
244 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700245
Ed Tanous002d39b2022-05-31 08:59:27 -0700246 for (const std::string& id : subscripIds)
247 {
248 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800249 member["@odata.id"] = boost::urls::format(
250 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500251 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700252 }
Chicago Duan3d307082020-11-26 14:12:12 +0800253 crow::connections::systemBus->async_method_call(
Ed Tanouse81de512023-06-27 17:07:00 -0700254 [asyncResp](const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800255 const dbus::utility::ManagedObjectType& resp) {
256 doSubscriptionCollection(ec, asyncResp, resp);
257 },
258 "xyz.openbmc_project.Network.SNMP",
259 "/xyz/openbmc_project/network/snmp/manager",
260 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous002d39b2022-05-31 08:59:27 -0700261 });
Chicago Duan3d307082020-11-26 14:12:12 +0800262
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700263 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500264 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700265 .methods(boost::beast::http::verb::post)(
266 [&app](const crow::Request& req,
267 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000268 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700269 {
270 return;
271 }
272 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
273 maxNoOfSubscriptions)
274 {
275 messages::eventSubscriptionLimitExceeded(asyncResp->res);
276 return;
277 }
278 std::string destUrl;
279 std::string protocol;
280 std::optional<std::string> context;
281 std::optional<std::string> subscriptionType;
282 std::optional<std::string> eventFormatType2;
283 std::optional<std::string> retryPolicy;
284 std::optional<std::vector<std::string>> msgIds;
285 std::optional<std::vector<std::string>> regPrefixes;
286 std::optional<std::vector<std::string>> resTypes;
287 std::optional<std::vector<nlohmann::json>> headers;
288 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800289
Ed Tanous002d39b2022-05-31 08:59:27 -0700290 if (!json_util::readJsonPatch(
291 req, asyncResp->res, "Destination", destUrl, "Context", context,
292 "Protocol", protocol, "SubscriptionType", subscriptionType,
293 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
294 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
295 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
296 mrdJsonArray, "ResourceTypes", resTypes))
297 {
298 return;
299 }
300
AppaRao Puli600af5f2021-10-06 21:51:16 +0000301 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
302 static constexpr const uint16_t maxDestinationSize = 2000;
303 if (destUrl.size() > maxDestinationSize)
304 {
305 messages::stringValueTooLong(asyncResp->res, "Destination",
306 maxDestinationSize);
307 return;
308 }
309
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 if (regPrefixes && msgIds)
311 {
312 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800313 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 messages::propertyValueConflict(asyncResp->res, "MessageIds",
315 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800316 return;
317 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800319
Ed Tanous002d39b2022-05-31 08:59:27 -0700320 std::string host;
321 std::string urlProto;
322 uint16_t port = 0;
323 std::string path;
324
325 if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
326 path))
327 {
Ed Tanous62598e32023-07-17 17:06:25 -0700328 BMCWEB_LOG_WARNING("Failed to validate and split destination url");
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 messages::propertyValueFormatError(asyncResp->res, destUrl,
330 "Destination");
331 return;
332 }
333
Chicago Duan3d307082020-11-26 14:12:12 +0800334 if (protocol == "SNMPv2c")
335 {
336 if (context)
337 {
338 messages::propertyValueConflict(asyncResp->res, "Context",
339 "Protocol");
340 return;
341 }
342 if (eventFormatType2)
343 {
344 messages::propertyValueConflict(asyncResp->res,
345 "EventFormatType", "Protocol");
346 return;
347 }
348 if (retryPolicy)
349 {
350 messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
351 "Protocol");
352 return;
353 }
354 if (msgIds)
355 {
356 messages::propertyValueConflict(asyncResp->res, "MessageIds",
357 "Protocol");
358 return;
359 }
360 if (regPrefixes)
361 {
362 messages::propertyValueConflict(asyncResp->res,
363 "RegistryPrefixes", "Protocol");
364 return;
365 }
366 if (resTypes)
367 {
368 messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
369 "Protocol");
370 return;
371 }
372 if (headers)
373 {
374 messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
375 "Protocol");
376 return;
377 }
378 if (mrdJsonArray)
379 {
380 messages::propertyValueConflict(
381 asyncResp->res, "MetricReportDefinitions", "Protocol");
382 return;
383 }
384
385 addSnmpTrapClient(asyncResp, host, port);
386 return;
387 }
388
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 if (path.empty())
390 {
391 path = "/";
392 }
Chicago Duan3d307082020-11-26 14:12:12 +0800393
Ed Tanousf8ca6d72022-06-28 12:12:03 -0700394 std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
395 host, port, path, urlProto, app.ioContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700396
397 subValue->destinationUrl = destUrl;
398
399 if (subscriptionType)
400 {
401 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800402 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700403 messages::propertyValueNotInList(
404 asyncResp->res, *subscriptionType, "SubscriptionType");
405 return;
406 }
407 subValue->subscriptionType = *subscriptionType;
408 }
409 else
410 {
411 subValue->subscriptionType = "RedfishEvent"; // Default
412 }
413
414 if (protocol != "Redfish")
415 {
416 messages::propertyValueNotInList(asyncResp->res, protocol,
417 "Protocol");
418 return;
419 }
420 subValue->protocol = protocol;
421
422 if (eventFormatType2)
423 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700424 if (std::ranges::find(supportedEvtFormatTypes, *eventFormatType2) ==
425 supportedEvtFormatTypes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700426 {
427 messages::propertyValueNotInList(
428 asyncResp->res, *eventFormatType2, "EventFormatType");
429 return;
430 }
431 subValue->eventFormatType = *eventFormatType2;
432 }
433 else
434 {
435 // If not specified, use default "Event"
436 subValue->eventFormatType = "Event";
437 }
438
439 if (context)
440 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000441 // This value is selected aribitrarily.
442 constexpr const size_t maxContextSize = 256;
443 if (context->size() > maxContextSize)
444 {
445 messages::stringValueTooLong(asyncResp->res, "Context",
446 maxContextSize);
447 return;
448 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 subValue->customText = *context;
450 }
451
452 if (headers)
453 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000454 size_t cumulativeLen = 0;
455
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 for (const nlohmann::json& headerChunk : *headers)
457 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000458 std::string hdr{headerChunk.dump(
459 -1, ' ', true, nlohmann::json::error_handler_t::replace)};
460 cumulativeLen += hdr.length();
461
462 // This value is selected to mirror http_connection.hpp
463 constexpr const uint16_t maxHeaderSizeED = 8096;
464 if (cumulativeLen > maxHeaderSizeED)
465 {
466 messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
467 maxHeaderSizeED);
468 return;
469 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700470 for (const auto& item : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700471 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700472 const std::string* value =
473 item.value().get_ptr<const std::string*>();
474 if (value == nullptr)
475 {
476 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700477 asyncResp->res, item.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 "HttpHeaders/" + item.key());
479 return;
480 }
481 subValue->httpHeaders.set(item.key(), *value);
482 }
483 }
484 }
485
486 if (regPrefixes)
487 {
488 for (const std::string& it : *regPrefixes)
489 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700490 if (std::ranges::find(supportedRegPrefixes, it) ==
491 supportedRegPrefixes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700492 {
493 messages::propertyValueNotInList(asyncResp->res, it,
494 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530495 return;
496 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800497 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700498 subValue->registryPrefixes = *regPrefixes;
499 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530500
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 if (resTypes)
502 {
503 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800504 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700505 if (std::ranges::find(supportedResourceTypes, it) ==
506 supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700507 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 messages::propertyValueNotInList(asyncResp->res, it,
509 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530510 return;
511 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700512 }
513 subValue->resourceTypes = *resTypes;
514 }
515
516 if (msgIds)
517 {
518 std::vector<std::string> registryPrefix;
519
520 // If no registry prefixes are mentioned, consider all
521 // supported prefixes
522 if (subValue->registryPrefixes.empty())
523 {
524 registryPrefix.assign(supportedRegPrefixes.begin(),
525 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800526 }
527 else
528 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700529 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800530 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530531
Ed Tanous002d39b2022-05-31 08:59:27 -0700532 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800533 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800535
Ed Tanous002d39b2022-05-31 08:59:27 -0700536 // Check for Message ID in each of the selected Registry
537 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700538 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700539 const std::span<const redfish::registries::MessageEntry>
540 registry =
541 redfish::registries::getRegistryFromPrefix(it);
542
Ed Tanous3544d2a2023-08-06 18:12:20 -0700543 if (std::ranges::any_of(
544 registry,
Ed Tanous002d39b2022-05-31 08:59:27 -0700545 [&id](const redfish::registries::MessageEntry&
546 messageEntry) {
547 return id == messageEntry.first;
548 }))
549 {
550 validId = true;
551 break;
552 }
553 }
554
555 if (!validId)
556 {
557 messages::propertyValueNotInList(asyncResp->res, id,
558 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800559 return;
560 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800561 }
562
Ed Tanous002d39b2022-05-31 08:59:27 -0700563 subValue->registryMsgIds = *msgIds;
564 }
565
566 if (retryPolicy)
567 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700568 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
569 supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800570 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
572 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800573 return;
574 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 subValue->retryPolicy = *retryPolicy;
576 }
577 else
578 {
579 // Default "TerminateAfterRetries"
580 subValue->retryPolicy = "TerminateAfterRetries";
581 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800582
Ed Tanous002d39b2022-05-31 08:59:27 -0700583 if (mrdJsonArray)
584 {
585 for (nlohmann::json& mrdObj : *mrdJsonArray)
586 {
587 std::string mrdUri;
588
589 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
590 mrdUri))
591
592 {
593 return;
594 }
595 subValue->metricReportDefinitions.emplace_back(mrdUri);
596 }
597 }
598
599 std::string id =
600 EventServiceManager::getInstance().addSubscription(subValue);
601 if (id.empty())
602 {
603 messages::internalError(asyncResp->res);
604 return;
605 }
606
607 messages::created(asyncResp->res);
608 asyncResp->res.addHeader(
609 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800610 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700611}
612
613inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530614{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500615 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700616 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700617 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700618 [&app](const crow::Request& req,
619 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
620 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000621 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700622 {
623 return;
624 }
Chicago Duan3d307082020-11-26 14:12:12 +0800625
626 if (param.starts_with("snmp"))
627 {
628 getSnmpTrapClient(asyncResp, param);
629 return;
630 }
631
Ed Tanous002d39b2022-05-31 08:59:27 -0700632 std::shared_ptr<Subscription> subValue =
633 EventServiceManager::getInstance().getSubscription(param);
634 if (subValue == nullptr)
635 {
636 asyncResp->res.result(boost::beast::http::status::not_found);
637 return;
638 }
639 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530640
Ed Tanous002d39b2022-05-31 08:59:27 -0700641 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800642 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous002d39b2022-05-31 08:59:27 -0700643 asyncResp->res.jsonValue["Protocol"] = "Redfish";
Ed Tanous3b327802023-08-14 09:23:43 -0700644 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
645 "/redfish/v1/EventService/Subscriptions/{}", id);
Ed Tanous002d39b2022-05-31 08:59:27 -0700646 asyncResp->res.jsonValue["Id"] = id;
647 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
648 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
649 asyncResp->res.jsonValue["Context"] = subValue->customText;
650 asyncResp->res.jsonValue["SubscriptionType"] =
651 subValue->subscriptionType;
652 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
653 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
654 asyncResp->res.jsonValue["RegistryPrefixes"] =
655 subValue->registryPrefixes;
656 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800657
Ed Tanous002d39b2022-05-31 08:59:27 -0700658 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
659 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530660
Ed Tanous002d39b2022-05-31 08:59:27 -0700661 nlohmann::json::array_t mrdJsonArray;
662 for (const auto& mdrUri : subValue->metricReportDefinitions)
663 {
664 nlohmann::json::object_t mdr;
665 mdr["@odata.id"] = mdrUri;
666 mrdJsonArray.emplace_back(std::move(mdr));
667 }
668 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
669 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500670 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700671 // The below privilege is wrong, it should be ConfigureManager OR
672 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500673 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700674 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700675 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700676 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700677 [&app](const crow::Request& req,
678 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
679 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000680 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700681 {
682 return;
683 }
684 std::shared_ptr<Subscription> subValue =
685 EventServiceManager::getInstance().getSubscription(param);
686 if (subValue == nullptr)
687 {
688 asyncResp->res.result(boost::beast::http::status::not_found);
689 return;
690 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530691
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 std::optional<std::string> context;
693 std::optional<std::string> retryPolicy;
694 std::optional<std::vector<nlohmann::json>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500695
Ed Tanous002d39b2022-05-31 08:59:27 -0700696 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
697 "DeliveryRetryPolicy", retryPolicy,
698 "HttpHeaders", headers))
699 {
700 return;
701 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530702
Ed Tanous002d39b2022-05-31 08:59:27 -0700703 if (context)
704 {
705 subValue->customText = *context;
706 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530707
Ed Tanous002d39b2022-05-31 08:59:27 -0700708 if (headers)
709 {
710 boost::beast::http::fields fields;
711 for (const nlohmann::json& headerChunk : *headers)
712 {
Patrick Williams62bafc02022-09-08 17:35:35 -0500713 for (const auto& it : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700714 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700715 const std::string* value =
716 it.value().get_ptr<const std::string*>();
717 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700718 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700719 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700720 asyncResp->res, it.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700721 "HttpHeaders/" + it.key());
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700722 return;
723 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700724 fields.set(it.key(), *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700725 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700726 }
727 subValue->httpHeaders = fields;
728 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530729
Ed Tanous002d39b2022-05-31 08:59:27 -0700730 if (retryPolicy)
731 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700732 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
733 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700734 {
735 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
736 "DeliveryRetryPolicy");
737 return;
738 }
739 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700740 }
741
742 EventServiceManager::getInstance().updateSubscriptionData();
743 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500744 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700745 // The below privilege is wrong, it should be ConfigureManager OR
746 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500747 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700748 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700749 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700750 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700751 [&app](const crow::Request& req,
752 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
753 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000754 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700755 {
756 return;
757 }
Chicago Duan3d307082020-11-26 14:12:12 +0800758
759 if (param.starts_with("snmp"))
760 {
761 deleteSnmpTrapClient(asyncResp, param);
762 EventServiceManager::getInstance().deleteSubscription(param);
763 return;
764 }
765
Ed Tanous002d39b2022-05-31 08:59:27 -0700766 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
767 {
768 asyncResp->res.result(boost::beast::http::status::not_found);
769 return;
770 }
771 EventServiceManager::getInstance().deleteSubscription(param);
772 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700773}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530774
775} // namespace redfish