blob: 73075717033f4b7aa15f1040421be936be9b1705 [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>
Ed Tanousa716aa72023-08-01 11:35:53 -070027#include <boost/url/parse.hpp>
Chicago Duan3d307082020-11-26 14:12:12 +080028#include <sdbusplus/unpack_properties.hpp>
29#include <utils/dbus_utils.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070030
Chicago Duan3d307082020-11-26 14:12:12 +080031#include <charconv>
32#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070033#include <ranges>
Patrick Williams1e270c52021-12-04 06:06:56 -060034#include <span>
Chicago Duan3d307082020-11-26 14:12:12 +080035#include <string>
Patrick Williams1e270c52021-12-04 06:06:56 -060036
AppaRao Pulie5aaf042020-03-20 01:05:52 +053037namespace redfish
38{
39
AppaRao Puli156d6b02020-04-25 06:04:05 +053040static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
41 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053042static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +053043 "Base", "OpenBMC", "TaskEvent"};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053044static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
45 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
46
Sunitha Harishe56f2542020-07-22 02:38:59 -050047static constexpr const std::array<const char*, 1> supportedResourceTypes = {
48 "Task"};
Sunitha Harishe56f2542020-07-22 02:38:59 -050049
John Edward Broadbent7e860f12021-04-08 15:57:16 -070050inline void requestRoutesEventService(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +053051{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -070053 .privileges(redfish::privileges::getEventService)
Ed Tanous002d39b2022-05-31 08:59:27 -070054 .methods(boost::beast::http::verb::get)(
55 [&app](const crow::Request& req,
56 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000057 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070058 {
59 return;
60 }
Ed Tanous14766872022-03-15 10:44:42 -070061
Ed Tanous002d39b2022-05-31 08:59:27 -070062 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
63 asyncResp->res.jsonValue["@odata.type"] =
64 "#EventService.v1_5_0.EventService";
65 asyncResp->res.jsonValue["Id"] = "EventService";
66 asyncResp->res.jsonValue["Name"] = "Event Service";
AppaRao Puli5e44e3d2021-03-16 15:37:24 +000067 asyncResp->res.jsonValue["ServerSentEventUri"] =
68 "/redfish/v1/EventService/SSE";
69
Ed Tanous002d39b2022-05-31 08:59:27 -070070 asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
71 "/redfish/v1/EventService/Subscriptions";
72 asyncResp->res
73 .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
74 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
AppaRao Pulie5aaf042020-03-20 01:05:52 +053075
Ed Tanous002d39b2022-05-31 08:59:27 -070076 const persistent_data::EventServiceConfig eventServiceConfig =
77 persistent_data::EventServiceStore::getInstance()
78 .getEventServiceConfig();
zhanghch058d1b46d2021-04-01 11:18:24 +080079
Ed Tanous002d39b2022-05-31 08:59:27 -070080 asyncResp->res.jsonValue["Status"]["State"] =
81 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
82 asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
83 asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
84 eventServiceConfig.retryAttempts;
85 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
86 eventServiceConfig.retryTimeoutInterval;
87 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
88 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
89 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053090
Ed Tanous613dabe2022-07-09 11:17:36 -070091 nlohmann::json::object_t supportedSSEFilters;
92 supportedSSEFilters["EventFormatType"] = true;
93 supportedSSEFilters["MessageId"] = true;
94 supportedSSEFilters["MetricReportDefinition"] = true;
95 supportedSSEFilters["RegistryPrefix"] = true;
96 supportedSSEFilters["OriginResource"] = false;
97 supportedSSEFilters["ResourceType"] = false;
AppaRao Puli7d1cc382020-05-16 02:42:22 +053098
Ed Tanous002d39b2022-05-31 08:59:27 -070099 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
Ed Tanous613dabe2022-07-09 11:17:36 -0700100 std::move(supportedSSEFilters);
Patrick Williams5a39f772023-10-20 11:20:21 -0500101 });
Ayushi Smriti07941a82020-05-21 15:55:34 +0530102
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700103 BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
Ed Tanoused398212021-06-09 17:05:54 -0700104 .privileges(redfish::privileges::patchEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700105 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700106 [&app](const crow::Request& req,
107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000108 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700109 {
110 return;
111 }
112 std::optional<bool> serviceEnabled;
113 std::optional<uint32_t> retryAttemps;
114 std::optional<uint32_t> retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530115
Ed Tanous002d39b2022-05-31 08:59:27 -0700116 if (!json_util::readJsonPatch(
117 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
118 "DeliveryRetryAttempts", retryAttemps,
119 "DeliveryRetryIntervalSeconds", retryInterval))
120 {
121 return;
122 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530123
Ed Tanous002d39b2022-05-31 08:59:27 -0700124 persistent_data::EventServiceConfig eventServiceConfig =
125 persistent_data::EventServiceStore::getInstance()
126 .getEventServiceConfig();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700127
Ed Tanous002d39b2022-05-31 08:59:27 -0700128 if (serviceEnabled)
129 {
130 eventServiceConfig.enabled = *serviceEnabled;
131 }
Sunitha Harishe56f2542020-07-22 02:38:59 -0500132
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 if (retryAttemps)
134 {
135 // Supported range [1-3]
136 if ((*retryAttemps < 1) || (*retryAttemps > 3))
137 {
138 messages::queryParameterOutOfRange(
139 asyncResp->res, std::to_string(*retryAttemps),
140 "DeliveryRetryAttempts", "[1-3]");
141 }
142 else
143 {
144 eventServiceConfig.retryAttempts = *retryAttemps;
145 }
146 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 if (retryInterval)
149 {
Gunnar Mills33a32b32022-11-17 14:29:07 -0600150 // Supported range [5 - 180]
151 if ((*retryInterval < 5) || (*retryInterval > 180))
Ed Tanous002d39b2022-05-31 08:59:27 -0700152 {
153 messages::queryParameterOutOfRange(
154 asyncResp->res, std::to_string(*retryInterval),
Gunnar Mills33a32b32022-11-17 14:29:07 -0600155 "DeliveryRetryIntervalSeconds", "[5-180]");
Ed Tanous002d39b2022-05-31 08:59:27 -0700156 }
157 else
158 {
159 eventServiceConfig.retryTimeoutInterval = *retryInterval;
160 }
161 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700162
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 EventServiceManager::getInstance().setEventServiceConfig(
164 eventServiceConfig);
Patrick Williams5a39f772023-10-20 11:20:21 -0500165 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700166}
167
168inline void requestRoutesSubmitTestEvent(App& app)
169{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170 BMCWEB_ROUTE(
171 app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
Ed Tanoused398212021-06-09 17:05:54 -0700172 .privileges(redfish::privileges::postEventService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700173 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700174 [&app](const crow::Request& req,
175 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000176 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700177 {
178 return;
179 }
180 if (!EventServiceManager::getInstance().sendTestEventLog())
181 {
182 messages::serviceDisabled(asyncResp->res,
183 "/redfish/v1/EventService/");
184 return;
185 }
186 asyncResp->res.result(boost::beast::http::status::no_content);
Patrick Williams5a39f772023-10-20 11:20:21 -0500187 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700188}
189
Chicago Duan3d307082020-11-26 14:12:12 +0800190inline void doSubscriptionCollection(
Ed Tanouse81de512023-06-27 17:07:00 -0700191 const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
193 const dbus::utility::ManagedObjectType& resp)
194{
195 if (ec)
196 {
Ed Tanous13061012023-07-25 11:12:19 -0700197 if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
Chicago Duan3d307082020-11-26 14:12:12 +0800198 {
199 // This is an optional process so just return if it isn't there
200 return;
201 }
202
Ed Tanous62598e32023-07-17 17:06:25 -0700203 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
Chicago Duan3d307082020-11-26 14:12:12 +0800204 messages::internalError(asyncResp->res);
205 return;
206 }
207 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
208 for (const auto& objpath : resp)
209 {
210 sdbusplus::message::object_path path(objpath.first);
211 const std::string snmpId = path.filename();
212 if (snmpId.empty())
213 {
Ed Tanous62598e32023-07-17 17:06:25 -0700214 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
Chicago Duan3d307082020-11-26 14:12:12 +0800215 messages::internalError(asyncResp->res);
216 return;
217 }
218
219 getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
220 }
221}
222
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700223inline void requestRoutesEventDestinationCollection(App& app)
224{
Gayathri Leburu1ebe3e42022-02-09 10:45:19 +0000225 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Ed Tanoused398212021-06-09 17:05:54 -0700226 .privileges(redfish::privileges::getEventDestinationCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700227 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700228 [&app](const crow::Request& req,
229 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000230 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700231 {
232 return;
233 }
234 asyncResp->res.jsonValue["@odata.type"] =
235 "#EventDestinationCollection.EventDestinationCollection";
236 asyncResp->res.jsonValue["@odata.id"] =
237 "/redfish/v1/EventService/Subscriptions";
238 asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700239
Ed Tanous002d39b2022-05-31 08:59:27 -0700240 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700241
Ed Tanous002d39b2022-05-31 08:59:27 -0700242 std::vector<std::string> subscripIds =
243 EventServiceManager::getInstance().getAllIDs();
244 memberArray = nlohmann::json::array();
245 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700246
Ed Tanous002d39b2022-05-31 08:59:27 -0700247 for (const std::string& id : subscripIds)
248 {
249 nlohmann::json::object_t member;
Chicago Duan3d307082020-11-26 14:12:12 +0800250 member["@odata.id"] = boost::urls::format(
251 "/redfish/v1/EventService/Subscriptions/{}" + id);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500252 memberArray.emplace_back(std::move(member));
Ed Tanous002d39b2022-05-31 08:59:27 -0700253 }
Chicago Duan3d307082020-11-26 14:12:12 +0800254 crow::connections::systemBus->async_method_call(
Ed Tanouse81de512023-06-27 17:07:00 -0700255 [asyncResp](const boost::system::error_code& ec,
Chicago Duan3d307082020-11-26 14:12:12 +0800256 const dbus::utility::ManagedObjectType& resp) {
257 doSubscriptionCollection(ec, asyncResp, resp);
Patrick Williams5a39f772023-10-20 11:20:21 -0500258 },
Chicago Duan3d307082020-11-26 14:12:12 +0800259 "xyz.openbmc_project.Network.SNMP",
260 "/xyz/openbmc_project/network/snmp/manager",
261 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Patrick Williams5a39f772023-10-20 11:20:21 -0500262 });
Chicago Duan3d307082020-11-26 14:12:12 +0800263
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700264 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500265 .privileges(redfish::privileges::postEventDestinationCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700266 .methods(boost::beast::http::verb::post)(
267 [&app](const crow::Request& req,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000269 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700270 {
271 return;
272 }
273 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
274 maxNoOfSubscriptions)
275 {
276 messages::eventSubscriptionLimitExceeded(asyncResp->res);
277 return;
278 }
279 std::string destUrl;
280 std::string protocol;
Ed Tanous19bb3622024-07-05 10:07:40 -0500281 std::optional<bool> verifyCertificate;
Ed Tanous002d39b2022-05-31 08:59:27 -0700282 std::optional<std::string> context;
283 std::optional<std::string> subscriptionType;
284 std::optional<std::string> eventFormatType2;
285 std::optional<std::string> retryPolicy;
286 std::optional<std::vector<std::string>> msgIds;
287 std::optional<std::vector<std::string>> regPrefixes;
288 std::optional<std::vector<std::string>> resTypes;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800289 std::optional<std::vector<nlohmann::json::object_t>> headers;
290 std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800291
Ed Tanous002d39b2022-05-31 08:59:27 -0700292 if (!json_util::readJsonPatch(
293 req, asyncResp->res, "Destination", destUrl, "Context", context,
294 "Protocol", protocol, "SubscriptionType", subscriptionType,
295 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
296 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
297 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
Ed Tanous19bb3622024-07-05 10:07:40 -0500298 mrdJsonArray, "ResourceTypes", resTypes, "VerifyCertificate",
299 verifyCertificate))
Ed Tanous002d39b2022-05-31 08:59:27 -0700300 {
301 return;
302 }
303
AppaRao Puli600af5f2021-10-06 21:51:16 +0000304 // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
305 static constexpr const uint16_t maxDestinationSize = 2000;
306 if (destUrl.size() > maxDestinationSize)
307 {
308 messages::stringValueTooLong(asyncResp->res, "Destination",
309 maxDestinationSize);
310 return;
311 }
312
Ed Tanous002d39b2022-05-31 08:59:27 -0700313 if (regPrefixes && msgIds)
314 {
315 if (!regPrefixes->empty() && !msgIds->empty())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800316 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 messages::propertyValueConflict(asyncResp->res, "MessageIds",
318 "RegistryPrefixes");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800319 return;
320 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800322
Ed Tanous6fd29552023-10-04 09:40:14 -0700323 boost::system::result<boost::urls::url> url =
Ed Tanousa716aa72023-08-01 11:35:53 -0700324 boost::urls::parse_absolute_uri(destUrl);
325 if (!url)
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 {
Ed Tanous62598e32023-07-17 17:06:25 -0700327 BMCWEB_LOG_WARNING("Failed to validate and split destination url");
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 messages::propertyValueFormatError(asyncResp->res, destUrl,
329 "Destination");
330 return;
331 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700332 url->normalize();
333 crow::utility::setProtocolDefaults(*url, protocol);
334 crow::utility::setPortDefaults(*url);
335
336 if (url->path().empty())
337 {
338 url->set_path("/");
339 }
340
341 if (url->has_userinfo())
342 {
343 messages::propertyValueFormatError(asyncResp->res, destUrl,
344 "Destination");
345 return;
346 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700347
Chicago Duan3d307082020-11-26 14:12:12 +0800348 if (protocol == "SNMPv2c")
349 {
350 if (context)
351 {
352 messages::propertyValueConflict(asyncResp->res, "Context",
353 "Protocol");
354 return;
355 }
356 if (eventFormatType2)
357 {
358 messages::propertyValueConflict(asyncResp->res,
359 "EventFormatType", "Protocol");
360 return;
361 }
362 if (retryPolicy)
363 {
364 messages::propertyValueConflict(asyncResp->res, "RetryPolicy",
365 "Protocol");
366 return;
367 }
368 if (msgIds)
369 {
370 messages::propertyValueConflict(asyncResp->res, "MessageIds",
371 "Protocol");
372 return;
373 }
374 if (regPrefixes)
375 {
376 messages::propertyValueConflict(asyncResp->res,
377 "RegistryPrefixes", "Protocol");
378 return;
379 }
380 if (resTypes)
381 {
382 messages::propertyValueConflict(asyncResp->res, "ResourceTypes",
383 "Protocol");
384 return;
385 }
386 if (headers)
387 {
388 messages::propertyValueConflict(asyncResp->res, "HttpHeaders",
389 "Protocol");
390 return;
391 }
392 if (mrdJsonArray)
393 {
394 messages::propertyValueConflict(
395 asyncResp->res, "MetricReportDefinitions", "Protocol");
396 return;
397 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700398 if (url->scheme() != "snmp")
399 {
400 messages::propertyValueConflict(asyncResp->res, "Destination",
401 "Protocol");
402 return;
403 }
Chicago Duan3d307082020-11-26 14:12:12 +0800404
Ed Tanousa716aa72023-08-01 11:35:53 -0700405 addSnmpTrapClient(asyncResp, url->host_address(),
406 url->port_number());
Chicago Duan3d307082020-11-26 14:12:12 +0800407 return;
408 }
409
Ed Tanousa716aa72023-08-01 11:35:53 -0700410 std::shared_ptr<Subscription> subValue =
411 std::make_shared<Subscription>(*url, app.ioContext());
Chicago Duan3d307082020-11-26 14:12:12 +0800412
Ed Tanousa716aa72023-08-01 11:35:53 -0700413 subValue->destinationUrl = std::move(*url);
Ed Tanous002d39b2022-05-31 08:59:27 -0700414
415 if (subscriptionType)
416 {
417 if (*subscriptionType != "RedfishEvent")
Ed Tanousfffb8c12022-02-07 23:53:03 -0800418 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 messages::propertyValueNotInList(
420 asyncResp->res, *subscriptionType, "SubscriptionType");
421 return;
422 }
423 subValue->subscriptionType = *subscriptionType;
424 }
425 else
426 {
427 subValue->subscriptionType = "RedfishEvent"; // Default
428 }
429
430 if (protocol != "Redfish")
431 {
432 messages::propertyValueNotInList(asyncResp->res, protocol,
433 "Protocol");
434 return;
435 }
436 subValue->protocol = protocol;
437
Ed Tanous19bb3622024-07-05 10:07:40 -0500438 if (verifyCertificate)
439 {
440 subValue->verifyCertificate = *verifyCertificate;
441 }
442
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 if (eventFormatType2)
444 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700445 if (std::ranges::find(supportedEvtFormatTypes, *eventFormatType2) ==
446 supportedEvtFormatTypes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700447 {
448 messages::propertyValueNotInList(
449 asyncResp->res, *eventFormatType2, "EventFormatType");
450 return;
451 }
452 subValue->eventFormatType = *eventFormatType2;
453 }
454 else
455 {
456 // If not specified, use default "Event"
457 subValue->eventFormatType = "Event";
458 }
459
460 if (context)
461 {
Ed Tanous8ece0e42024-01-02 13:16:50 -0800462 // This value is selected arbitrarily.
AppaRao Puli600af5f2021-10-06 21:51:16 +0000463 constexpr const size_t maxContextSize = 256;
464 if (context->size() > maxContextSize)
465 {
466 messages::stringValueTooLong(asyncResp->res, "Context",
467 maxContextSize);
468 return;
469 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700470 subValue->customText = *context;
471 }
472
473 if (headers)
474 {
AppaRao Puli600af5f2021-10-06 21:51:16 +0000475 size_t cumulativeLen = 0;
476
Ed Tanous78d4ec42024-03-06 17:36:33 -0800477 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800479 for (const auto& item : headerChunk)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700480 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 const std::string* value =
Ed Tanous78d4ec42024-03-06 17:36:33 -0800482 item.second.get_ptr<const std::string*>();
Ed Tanous002d39b2022-05-31 08:59:27 -0700483 if (value == nullptr)
484 {
485 messages::propertyValueFormatError(
Ed Tanous78d4ec42024-03-06 17:36:33 -0800486 asyncResp->res, item.second,
487 "HttpHeaders/" + item.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 return;
489 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800490 // Adding a new json value is the size of the key, +
491 // the size of the value + 2 * 2 quotes for each, +
492 // the colon and space between. example:
493 // "key": "value"
494 cumulativeLen += item.first.size() + value->size() + 6;
495 // This value is selected to mirror http_connection.hpp
496 constexpr const uint16_t maxHeaderSizeED = 8096;
497 if (cumulativeLen > maxHeaderSizeED)
498 {
499 messages::arraySizeTooLong(
500 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
501 return;
502 }
503 subValue->httpHeaders.set(item.first, *value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700504 }
505 }
506 }
507
508 if (regPrefixes)
509 {
510 for (const std::string& it : *regPrefixes)
511 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700512 if (std::ranges::find(supportedRegPrefixes, it) ==
513 supportedRegPrefixes.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 {
515 messages::propertyValueNotInList(asyncResp->res, it,
516 "RegistryPrefixes");
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530517 return;
518 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800519 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 subValue->registryPrefixes = *regPrefixes;
521 }
P Dheeraj Srujan Kumarb304bd72021-01-29 17:46:35 +0530522
Ed Tanous002d39b2022-05-31 08:59:27 -0700523 if (resTypes)
524 {
525 for (const std::string& it : *resTypes)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800526 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700527 if (std::ranges::find(supportedResourceTypes, it) ==
528 supportedResourceTypes.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700529 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700530 messages::propertyValueNotInList(asyncResp->res, it,
531 "ResourceTypes");
AppaRao Puli144b6312020-08-03 22:23:12 +0530532 return;
533 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 }
535 subValue->resourceTypes = *resTypes;
536 }
537
538 if (msgIds)
539 {
540 std::vector<std::string> registryPrefix;
541
542 // If no registry prefixes are mentioned, consider all
543 // supported prefixes
544 if (subValue->registryPrefixes.empty())
545 {
546 registryPrefix.assign(supportedRegPrefixes.begin(),
547 supportedRegPrefixes.end());
Ed Tanousfffb8c12022-02-07 23:53:03 -0800548 }
549 else
550 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700551 registryPrefix = subValue->registryPrefixes;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800552 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530553
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 for (const std::string& id : *msgIds)
Ed Tanousfffb8c12022-02-07 23:53:03 -0800555 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700556 bool validId = false;
Ed Tanousfffb8c12022-02-07 23:53:03 -0800557
Ed Tanous002d39b2022-05-31 08:59:27 -0700558 // Check for Message ID in each of the selected Registry
559 for (const std::string& it : registryPrefix)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700560 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700561 const std::span<const redfish::registries::MessageEntry>
562 registry =
563 redfish::registries::getRegistryFromPrefix(it);
564
Ed Tanous3544d2a2023-08-06 18:12:20 -0700565 if (std::ranges::any_of(
566 registry,
Ed Tanous002d39b2022-05-31 08:59:27 -0700567 [&id](const redfish::registries::MessageEntry&
568 messageEntry) {
569 return id == messageEntry.first;
Patrick Williams5a39f772023-10-20 11:20:21 -0500570 }))
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 {
572 validId = true;
573 break;
574 }
575 }
576
577 if (!validId)
578 {
579 messages::propertyValueNotInList(asyncResp->res, id,
580 "MessageIds");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800581 return;
582 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800583 }
584
Ed Tanous002d39b2022-05-31 08:59:27 -0700585 subValue->registryMsgIds = *msgIds;
586 }
587
588 if (retryPolicy)
589 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700590 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
591 supportedRetryPolicies.end())
Ed Tanousfffb8c12022-02-07 23:53:03 -0800592 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700593 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
594 "DeliveryRetryPolicy");
Ed Tanousfffb8c12022-02-07 23:53:03 -0800595 return;
596 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700597 subValue->retryPolicy = *retryPolicy;
598 }
599 else
600 {
601 // Default "TerminateAfterRetries"
602 subValue->retryPolicy = "TerminateAfterRetries";
603 }
Ed Tanousfffb8c12022-02-07 23:53:03 -0800604
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 if (mrdJsonArray)
606 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800607 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
Ed Tanous002d39b2022-05-31 08:59:27 -0700608 {
609 std::string mrdUri;
610
Ed Tanous78d4ec42024-03-06 17:36:33 -0800611 if (!json_util::readJsonObject(mrdObj, asyncResp->res,
612 "@odata.id", mrdUri))
Ed Tanous002d39b2022-05-31 08:59:27 -0700613
614 {
615 return;
616 }
617 subValue->metricReportDefinitions.emplace_back(mrdUri);
618 }
619 }
620
621 std::string id =
Ed Tanousf80a87f2024-06-16 12:10:33 -0700622 EventServiceManager::getInstance().addPushSubscription(subValue);
Ed Tanous002d39b2022-05-31 08:59:27 -0700623 if (id.empty())
624 {
625 messages::internalError(asyncResp->res);
626 return;
627 }
628
629 messages::created(asyncResp->res);
630 asyncResp->res.addHeader(
631 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
Patrick Williams5a39f772023-10-20 11:20:21 -0500632 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700633}
634
635inline void requestRoutesEventDestination(App& app)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530636{
Ravi Teja9d41aec2021-07-23 01:57:01 -0500637 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700638 .privileges(redfish::privileges::getEventDestination)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700639 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700640 [&app](const crow::Request& req,
641 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
642 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000643 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700644 {
645 return;
646 }
Chicago Duan3d307082020-11-26 14:12:12 +0800647
648 if (param.starts_with("snmp"))
649 {
650 getSnmpTrapClient(asyncResp, param);
651 return;
652 }
653
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 std::shared_ptr<Subscription> subValue =
655 EventServiceManager::getInstance().getSubscription(param);
656 if (subValue == nullptr)
657 {
658 asyncResp->res.result(boost::beast::http::status::not_found);
659 return;
660 }
661 const std::string& id = param;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530662
Ed Tanous002d39b2022-05-31 08:59:27 -0700663 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan3d307082020-11-26 14:12:12 +0800664 "#EventDestination.v1_8_0.EventDestination";
Ed Tanous002d39b2022-05-31 08:59:27 -0700665 asyncResp->res.jsonValue["Protocol"] = "Redfish";
Ed Tanous3b327802023-08-14 09:23:43 -0700666 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
667 "/redfish/v1/EventService/Subscriptions/{}", id);
Ed Tanous002d39b2022-05-31 08:59:27 -0700668 asyncResp->res.jsonValue["Id"] = id;
669 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
670 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
671 asyncResp->res.jsonValue["Context"] = subValue->customText;
672 asyncResp->res.jsonValue["SubscriptionType"] =
673 subValue->subscriptionType;
674 asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
675 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
676 asyncResp->res.jsonValue["RegistryPrefixes"] =
677 subValue->registryPrefixes;
678 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
zhanghch058d1b46d2021-04-01 11:18:24 +0800679
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
681 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
Ed Tanous19bb3622024-07-05 10:07:40 -0500682 asyncResp->res.jsonValue["VerifyCertificate"] =
683 subValue->verifyCertificate;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530684
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 nlohmann::json::array_t mrdJsonArray;
686 for (const auto& mdrUri : subValue->metricReportDefinitions)
687 {
688 nlohmann::json::object_t mdr;
689 mdr["@odata.id"] = mdrUri;
690 mrdJsonArray.emplace_back(std::move(mdr));
691 }
692 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
Patrick Williams5a39f772023-10-20 11:20:21 -0500693 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500694 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700695 // The below privilege is wrong, it should be ConfigureManager OR
696 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500697 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700698 //.privileges(redfish::privileges::patchEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700699 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700700 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700701 [&app](const crow::Request& req,
702 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
703 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000704 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 {
706 return;
707 }
708 std::shared_ptr<Subscription> subValue =
709 EventServiceManager::getInstance().getSubscription(param);
710 if (subValue == nullptr)
711 {
712 asyncResp->res.result(boost::beast::http::status::not_found);
713 return;
714 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530715
Ed Tanous002d39b2022-05-31 08:59:27 -0700716 std::optional<std::string> context;
717 std::optional<std::string> retryPolicy;
Ed Tanous19bb3622024-07-05 10:07:40 -0500718 std::optional<bool> verifyCertificate;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800719 std::optional<std::vector<nlohmann::json::object_t>> headers;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500720
Ed Tanous002d39b2022-05-31 08:59:27 -0700721 if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
Ed Tanous19bb3622024-07-05 10:07:40 -0500722 "VerifyCertificate", verifyCertificate,
Ed Tanous002d39b2022-05-31 08:59:27 -0700723 "DeliveryRetryPolicy", retryPolicy,
724 "HttpHeaders", headers))
725 {
726 return;
727 }
AppaRao Puli144b6312020-08-03 22:23:12 +0530728
Ed Tanous002d39b2022-05-31 08:59:27 -0700729 if (context)
730 {
731 subValue->customText = *context;
732 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530733
Ed Tanous002d39b2022-05-31 08:59:27 -0700734 if (headers)
735 {
736 boost::beast::http::fields fields;
Ed Tanous78d4ec42024-03-06 17:36:33 -0800737 for (const nlohmann::json::object_t& headerChunk : *headers)
Ed Tanous002d39b2022-05-31 08:59:27 -0700738 {
Ed Tanous78d4ec42024-03-06 17:36:33 -0800739 for (const auto& it : headerChunk)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700740 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700741 const std::string* value =
Ed Tanous78d4ec42024-03-06 17:36:33 -0800742 it.second.get_ptr<const std::string*>();
Ed Tanous002d39b2022-05-31 08:59:27 -0700743 if (value == nullptr)
Ed Tanous601c71a2021-09-08 16:40:12 -0700744 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 messages::propertyValueFormatError(
Ed Tanous78d4ec42024-03-06 17:36:33 -0800746 asyncResp->res, it.second,
747 "HttpHeaders/" + it.first);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700748 return;
749 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800750 fields.set(it.first, *value);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700751 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700752 }
Ed Tanous78d4ec42024-03-06 17:36:33 -0800753 subValue->httpHeaders = std::move(fields);
Ed Tanous002d39b2022-05-31 08:59:27 -0700754 }
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530755
Ed Tanous002d39b2022-05-31 08:59:27 -0700756 if (retryPolicy)
757 {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700758 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
759 supportedRetryPolicies.end())
Ed Tanous002d39b2022-05-31 08:59:27 -0700760 {
761 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
762 "DeliveryRetryPolicy");
763 return;
764 }
765 subValue->retryPolicy = *retryPolicy;
Ed Tanous002d39b2022-05-31 08:59:27 -0700766 }
767
Ed Tanous19bb3622024-07-05 10:07:40 -0500768 if (verifyCertificate)
769 {
770 subValue->verifyCertificate = *verifyCertificate;
771 }
772
Ed Tanous002d39b2022-05-31 08:59:27 -0700773 EventServiceManager::getInstance().updateSubscriptionData();
Patrick Williams5a39f772023-10-20 11:20:21 -0500774 });
Ravi Teja9d41aec2021-07-23 01:57:01 -0500775 BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700776 // The below privilege is wrong, it should be ConfigureManager OR
777 // ConfigureSelf
Abhishek Patel7eeafa72021-07-28 10:59:16 -0500778 // https://github.com/openbmc/bmcweb/issues/220
Ed Tanoused398212021-06-09 17:05:54 -0700779 //.privileges(redfish::privileges::deleteEventDestination)
Ed Tanous432a8902021-06-14 15:28:56 -0700780 .privileges({{"ConfigureManager"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700781 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700782 [&app](const crow::Request& req,
783 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
784 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000785 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700786 {
787 return;
788 }
Chicago Duan3d307082020-11-26 14:12:12 +0800789
790 if (param.starts_with("snmp"))
791 {
792 deleteSnmpTrapClient(asyncResp, param);
793 EventServiceManager::getInstance().deleteSubscription(param);
794 return;
795 }
796
Ed Tanous002d39b2022-05-31 08:59:27 -0700797 if (!EventServiceManager::getInstance().isSubscriptionExist(param))
798 {
799 asyncResp->res.result(boost::beast::http::status::not_found);
800 return;
801 }
802 EventServiceManager::getInstance().deleteSubscription(param);
Patrick Williams5a39f772023-10-20 11:20:21 -0500803 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700804}
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530805
806} // namespace redfish