blob: 4919dece5940ab2fbbd9e37c79afd35ee1353cac [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>
Patrick Williams1e270c52021-12-04 06:06:56 -060032#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080033#include <string>
Patrick Williams1e270c52021-12-04 06:06:56 -060034
AppaRao Pulie5aaf042020-03-20 01:05:52 +053035namespace redfish
36{
37
AppaRao Puli156d6b02020-04-25 06:04:05 +053038static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
39 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053040static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053041 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053042static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
43 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
44
Sunitha Harishe56f2542020-07-22 02:38:59 -050045static constexpr const std::array<const char*, 1> supportedResourceTypes = {
46 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050047
John Edward Broadbent7e860f12021-04-08 15:57:16 -070048inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053049{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070050 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070051 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070052 .methods(boost::beast::http::verb::get)(
53 [&app](const crow::Request& req,
54 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000055 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070056 {
57 return;
58 }
Ed Tanous14766872022-03-15 10:44:42 -070059
Ed Tanous002d39b2022-05-31 08:59:27 -070060 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
61 asyncResp->res.jsonValue["@odata.type"] =
62 "#EventService.v1_5_0.EventService";
63 asyncResp->res.jsonValue["Id"] = "EventService";
64 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000065 asyncResp->res.jsonValue["ServerSentEventUri"] =
66 "/redfish/v1/EventService/SSE";
67
Ed Tanous002d39b2022-05-31 08:59:27 -070068 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
69 "/redfish/v1/EventService/Subscriptions";
70 asyncResp->res
71 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
72 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053073
Ed Tanous002d39b2022-05-31 08:59:27 -070074 const persistent_data::EventServiceConfig eventServiceConfig =
75 persistent_data::EventServiceStore::getInstance()
76 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080077
Ed Tanous002d39b2022-05-31 08:59:27 -070078 asyncResp->res.jsonValue["Status"]["State"] =
79 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
80 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
81 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
82 eventServiceConfig.retryAttempts;
83 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
84 eventServiceConfig.retryTimeoutInterval;
85 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
86 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
87 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053088
Ed Tanous613dabe2022-07-09 11:17:36 -070089 nlohmann::json::object_t supportedSSEFilters;
90 supportedSSEFilters["EventFormatType"] = true;
91 supportedSSEFilters["MessageId"] = true;
92 supportedSSEFilters["MetricReportDefinition"] = true;
93 supportedSSEFilters["RegistryPrefix"] = true;
94 supportedSSEFilters["OriginResource"] = false;
95 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053096
Ed Tanous002d39b2022-05-31 08:59:27 -070097 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -070098 std::move(supportedSSEFilters);
George Liu0fda0f12021-11-16 10:06:17 +080099 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530100
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700101 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700102 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700103 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700104 [&app](const crow::Request& req,
105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000106 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700107 {
108 return;
109 }
110 std::optional<bool> serviceEnabled;
111 std::optional<uint32_t> retryAttemps;
112 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530113
Ed Tanous002d39b2022-05-31 08:59:27 -0700114 if (!json_util::readJsonPatch(
115 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
116 "DeliveryRetryAttempts", retryAttemps,
117 "DeliveryRetryIntervalSeconds", retryInterval))
118 {
119 return;
120 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530121
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 persistent_data::EventServiceConfig eventServiceConfig =
123 persistent_data::EventServiceStore::getInstance()
124 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700125
Ed Tanous002d39b2022-05-31 08:59:27 -0700126 if (serviceEnabled)
127 {
128 eventServiceConfig.enabled = *serviceEnabled;
129 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500130
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 if (retryAttemps)
132 {
133 // Supported range [1-3]
134 if ((*retryAttemps < 1) || (*retryAttemps > 3))
135 {
136 messages::queryParameterOutOfRange(
137 asyncResp->res, std::to_string(*retryAttemps),
138 "DeliveryRetryAttempts", "[1-3]");
139 }
140 else
141 {
142 eventServiceConfig.retryAttempts = *retryAttemps;
143 }
144 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 if (retryInterval)
147 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600148 // Supported range [5 - 180]
149 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 {
151 messages::queryParameterOutOfRange(
152 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600153 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 }
155 else
156 {
157 eventServiceConfig.retryTimeoutInterval = *retryInterval;
158 }
159 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700160
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 EventServiceManager::getInstance().setEventServiceConfig(
162 eventServiceConfig);
163 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700164}
165
166inline void requestRoutesSubmitTestEvent(App& app)
167{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700168 BMCWEB_ROUTE(
169 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700170 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700172 [&app](const crow::Request& req,
173 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000174 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 {
176 return;
177 }
178 if (!EventServiceManager::getInstance().sendTestEventLog())
179 {
180 messages::serviceDisabled(asyncResp->res,
181 "/redfish/v1/EventService/");
182 return;
183 }
184 asyncResp->res.result(boost::beast::http::status::no_content);
185 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700186}
187
Chicago Duan3d307082020-11-26 14:12:12 +0800188inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700189 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191 const dbus::utility::ManagedObjectType& resp)
192{
193 if (ec)
194 {
195 if (ec.value() == EBADR)
196 {
197 // This is an optional process so just return if it isn't there
198 return;
199 }
200
201 BMCWEB_LOG_ERROR << "D-Bus response error on GetManagedObjects " << ec;
202 messages::internalError(asyncResp->res);
203 return;
204 }
205 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
206 for (const auto& objpath : resp)
207 {
208 sdbusplus::message::object_path path(objpath.first);
209 const std::string snmpId = path.filename();
210 if (snmpId.empty())
211 {
212 BMCWEB_LOG_ERROR << "The SNMP client ID is wrong";
213 messages::internalError(asyncResp->res);
214 return;
215 }
216
217 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
218 }
219}
220
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700221inline void requestRoutesEventDestinationCollection(App& app)
222{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000223 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700224 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700225 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700226 [&app](const crow::Request& req,
227 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000228 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700229 {
230 return;
231 }
232 asyncResp->res.jsonValue["@odata.type"] =
233 "#EventDestinationCollection.EventDestinationCollection";
234 asyncResp->res.jsonValue["@odata.id"] =
235 "/redfish/v1/EventService/Subscriptions";
236 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700237
Ed Tanous002d39b2022-05-31 08:59:27 -0700238 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700239
Ed Tanous002d39b2022-05-31 08:59:27 -0700240 std::vector<std::string> subscripIds =
241 EventServiceManager::getInstance().getAllIDs();
242 memberArray = nlohmann::json::array();
243 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700244
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 for (const std::string& id : subscripIds)
246 {
247 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800248 member["@odata.id"] = boost::urls::format(
249 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500250 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700251 }
Chicago Duan3d307082020-11-26 14:12:12 +0800252 crow::connections::systemBus->async_method_call(
Ed Tanouse81de512023-06-27 17:07:00 -0700253 [asyncResp](const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800254 const dbus::utility::ManagedObjectType& resp) {
255 doSubscriptionCollection(ec, asyncResp, resp);
256 },
257 "xyz.openbmc_project.Network.SNMP",
258 "/xyz/openbmc_project/network/snmp/manager",
259 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 });
Chicago Duan3d307082020-11-26 14:12:12 +0800261
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700262 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500263 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700264 .methods(boost::beast::http::verb::post)(
265 [&app](const crow::Request& req,
266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000267 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700268 {
269 return;
270 }
271 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
272 maxNoOfSubscriptions)
273 {
274 messages::eventSubscriptionLimitExceeded(asyncResp->res);
275 return;
276 }
277 std::string destUrl;
278 std::string protocol;
279 std::optional<std::string> context;
280 std::optional<std::string> subscriptionType;
281 std::optional<std::string> eventFormatType2;
282 std::optional<std::string> retryPolicy;
283 std::optional<std::vector<std::string>> msgIds;
284 std::optional<std::vector<std::string>> regPrefixes;
285 std::optional<std::vector<std::string>> resTypes;
286 std::optional<std::vector<nlohmann::json>> headers;
287 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800288
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 if (!json_util::readJsonPatch(
290 req, asyncResp->res, "Destination", destUrl, "Context", context,
291 "Protocol", protocol, "SubscriptionType", subscriptionType,
292 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
293 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
294 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
295 mrdJsonArray, "ResourceTypes", resTypes))
296 {
297 return;
298 }
299
AppaRao Puli600af5f2021-10-06 21:51:16 +0000300 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
301 static constexpr const uint16_t maxDestinationSize = 2000;
302 if (destUrl.size() > maxDestinationSize)
303 {
304 messages::stringValueTooLong(asyncResp->res, "Destination",
305 maxDestinationSize);
306 return;
307 }
308
Ed Tanous002d39b2022-05-31 08:59:27 -0700309 if (regPrefixes && msgIds)
310 {
311 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800312 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700313 messages::propertyValueConflict(asyncResp->res, "MessageIds",
314 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800315 return;
316 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800318
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 std::string host;
320 std::string urlProto;
321 uint16_t port = 0;
322 std::string path;
323
324 if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
325 path))
326 {
327 BMCWEB_LOG_WARNING
328 << "Failed to validate and split destination url";
329 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 {
424 if (std::find(supportedEvtFormatTypes.begin(),
425 supportedEvtFormatTypes.end(),
426 *eventFormatType2) == supportedEvtFormatTypes.end())
427 {
428 messages::propertyValueNotInList(
429 asyncResp->res, *eventFormatType2, "EventFormatType");
430 return;
431 }
432 subValue->eventFormatType = *eventFormatType2;
433 }
434 else
435 {
436 // If not specified, use default "Event"
437 subValue->eventFormatType = "Event";
438 }
439
440 if (context)
441 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000442 // This value is selected aribitrarily.
443 constexpr const size_t maxContextSize = 256;
444 if (context->size() > maxContextSize)
445 {
446 messages::stringValueTooLong(asyncResp->res, "Context",
447 maxContextSize);
448 return;
449 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 subValue->customText = *context;
451 }
452
453 if (headers)
454 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000455 size_t cumulativeLen = 0;
456
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 for (const nlohmann::json& headerChunk : *headers)
458 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000459 std::string hdr{headerChunk.dump(
460 -1, ' ', true, nlohmann::json::error_handler_t::replace)};
461 cumulativeLen += hdr.length();
462
463 // This value is selected to mirror http_connection.hpp
464 constexpr const uint16_t maxHeaderSizeED = 8096;
465 if (cumulativeLen > maxHeaderSizeED)
466 {
467 messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
468 maxHeaderSizeED);
469 return;
470 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700471 for (const auto& item : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700472 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700473 const std::string* value =
474 item.value().get_ptr<const std::string*>();
475 if (value == nullptr)
476 {
477 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700478 asyncResp->res, item.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700479 "HttpHeaders/" + item.key());
480 return;
481 }
482 subValue->httpHeaders.set(item.key(), *value);
483 }
484 }
485 }
486
487 if (regPrefixes)
488 {
489 for (const std::string& it : *regPrefixes)
490 {
491 if (std::find(supportedRegPrefixes.begin(),
492 supportedRegPrefixes.end(),
493 it) == supportedRegPrefixes.end())
494 {
495 messages::propertyValueNotInList(asyncResp->res, it,
496 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530497 return;
498 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800499 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700500 subValue->registryPrefixes = *regPrefixes;
501 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530502
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 if (resTypes)
504 {
505 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800506 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 if (std::find(supportedResourceTypes.begin(),
508 supportedResourceTypes.end(),
509 it) == supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700510 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 messages::propertyValueNotInList(asyncResp->res, it,
512 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530513 return;
514 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700515 }
516 subValue->resourceTypes = *resTypes;
517 }
518
519 if (msgIds)
520 {
521 std::vector<std::string> registryPrefix;
522
523 // If no registry prefixes are mentioned, consider all
524 // supported prefixes
525 if (subValue->registryPrefixes.empty())
526 {
527 registryPrefix.assign(supportedRegPrefixes.begin(),
528 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800529 }
530 else
531 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700532 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800533 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530534
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800536 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700537 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800538
Ed Tanous002d39b2022-05-31 08:59:27 -0700539 // Check for Message ID in each of the selected Registry
540 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700541 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 const std::span<const redfish::registries::MessageEntry>
543 registry =
544 redfish::registries::getRegistryFromPrefix(it);
545
546 if (std::any_of(
547 registry.begin(), registry.end(),
548 [&id](const redfish::registries::MessageEntry&
549 messageEntry) {
550 return id == messageEntry.first;
551 }))
552 {
553 validId = true;
554 break;
555 }
556 }
557
558 if (!validId)
559 {
560 messages::propertyValueNotInList(asyncResp->res, id,
561 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800562 return;
563 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800564 }
565
Ed Tanous002d39b2022-05-31 08:59:27 -0700566 subValue->registryMsgIds = *msgIds;
567 }
568
569 if (retryPolicy)
570 {
571 if (std::find(supportedRetryPolicies.begin(),
572 supportedRetryPolicies.end(),
573 *retryPolicy) == supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800574 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
576 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800577 return;
578 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700579 subValue->retryPolicy = *retryPolicy;
580 }
581 else
582 {
583 // Default "TerminateAfterRetries"
584 subValue->retryPolicy = "TerminateAfterRetries";
585 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800586
Ed Tanous002d39b2022-05-31 08:59:27 -0700587 if (mrdJsonArray)
588 {
589 for (nlohmann::json& mrdObj : *mrdJsonArray)
590 {
591 std::string mrdUri;
592
593 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
594 mrdUri))
595
596 {
597 return;
598 }
599 subValue->metricReportDefinitions.emplace_back(mrdUri);
600 }
601 }
602
603 std::string id =
604 EventServiceManager::getInstance().addSubscription(subValue);
605 if (id.empty())
606 {
607 messages::internalError(asyncResp->res);
608 return;
609 }
610
611 messages::created(asyncResp->res);
612 asyncResp->res.addHeader(
613 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Ed Tanousfffb8c12022-02-07 23:53:03 -0800614 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700615}
616
617inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530618{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500619 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700620 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700622 [&app](const crow::Request& req,
623 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
624 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000625 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700626 {
627 return;
628 }
Chicago Duan3d307082020-11-26 14:12:12 +0800629
630 if (param.starts_with("snmp"))
631 {
632 getSnmpTrapClient(asyncResp, param);
633 return;
634 }
635
Ed Tanous002d39b2022-05-31 08:59:27 -0700636 std::shared_ptr<Subscription> subValue =
637 EventServiceManager::getInstance().getSubscription(param);
638 if (subValue == nullptr)
639 {
640 asyncResp->res.result(boost::beast::http::status::not_found);
641 return;
642 }
643 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530644
Ed Tanous002d39b2022-05-31 08:59:27 -0700645 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800646 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous002d39b2022-05-31 08:59:27 -0700647 asyncResp->res.jsonValue["Protocol"] = "Redfish";
648 asyncResp->res.jsonValue["@odata.id"] =
649 "/redfish/v1/EventService/Subscriptions/" + id;
650 asyncResp->res.jsonValue["Id"] = id;
651 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
652 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
653 asyncResp->res.jsonValue["Context"] = subValue->customText;
654 asyncResp->res.jsonValue["SubscriptionType"] =
655 subValue->subscriptionType;
656 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
657 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
658 asyncResp->res.jsonValue["RegistryPrefixes"] =
659 subValue->registryPrefixes;
660 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800661
Ed Tanous002d39b2022-05-31 08:59:27 -0700662 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
663 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530664
Ed Tanous002d39b2022-05-31 08:59:27 -0700665 nlohmann::json::array_t mrdJsonArray;
666 for (const auto& mdrUri : subValue->metricReportDefinitions)
667 {
668 nlohmann::json::object_t mdr;
669 mdr["@odata.id"] = mdrUri;
670 mrdJsonArray.emplace_back(std::move(mdr));
671 }
672 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
673 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500674 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700675 // The below privilege is wrong, it should be ConfigureManager OR
676 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500677 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700678 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700679 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700680 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700681 [&app](const crow::Request& req,
682 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
683 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000684 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 {
686 return;
687 }
688 std::shared_ptr<Subscription> subValue =
689 EventServiceManager::getInstance().getSubscription(param);
690 if (subValue == nullptr)
691 {
692 asyncResp->res.result(boost::beast::http::status::not_found);
693 return;
694 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530695
Ed Tanous002d39b2022-05-31 08:59:27 -0700696 std::optional<std::string> context;
697 std::optional<std::string> retryPolicy;
698 std::optional<std::vector<nlohmann::json>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500699
Ed Tanous002d39b2022-05-31 08:59:27 -0700700 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
701 "DeliveryRetryPolicy", retryPolicy,
702 "HttpHeaders", headers))
703 {
704 return;
705 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530706
Ed Tanous002d39b2022-05-31 08:59:27 -0700707 if (context)
708 {
709 subValue->customText = *context;
710 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530711
Ed Tanous002d39b2022-05-31 08:59:27 -0700712 if (headers)
713 {
714 boost::beast::http::fields fields;
715 for (const nlohmann::json& headerChunk : *headers)
716 {
Patrick Williams62bafc02022-09-08 17:35:35 -0500717 for (const auto& it : headerChunk.items())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700718 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700719 const std::string* value =
720 it.value().get_ptr<const std::string*>();
721 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700722 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700723 messages::propertyValueFormatError(
Ed Tanousf818b042022-06-27 13:17:35 -0700724 asyncResp->res, it.value(),
Ed Tanous002d39b2022-05-31 08:59:27 -0700725 "HttpHeaders/" + it.key());
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700726 return;
727 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700728 fields.set(it.key(), *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700729 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700730 }
731 subValue->httpHeaders = fields;
732 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530733
Ed Tanous002d39b2022-05-31 08:59:27 -0700734 if (retryPolicy)
735 {
736 if (std::find(supportedRetryPolicies.begin(),
737 supportedRetryPolicies.end(),
738 *retryPolicy) == supportedRetryPolicies.end())
739 {
740 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
741 "DeliveryRetryPolicy");
742 return;
743 }
744 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 }
746
747 EventServiceManager::getInstance().updateSubscriptionData();
748 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500749 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700750 // The below privilege is wrong, it should be ConfigureManager OR
751 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500752 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700753 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700754 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700755 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700756 [&app](const crow::Request& req,
757 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
758 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000759 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700760 {
761 return;
762 }
Chicago Duan3d307082020-11-26 14:12:12 +0800763
764 if (param.starts_with("snmp"))
765 {
766 deleteSnmpTrapClient(asyncResp, param);
767 EventServiceManager::getInstance().deleteSubscription(param);
768 return;
769 }
770
Ed Tanous002d39b2022-05-31 08:59:27 -0700771 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
772 {
773 asyncResp->res.result(boost::beast::http::status::not_found);
774 return;
775 }
776 EventServiceManager::getInstance().deleteSubscription(param);
777 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700778}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530779
780} // namespace redfish