blob: b532815e4df7934b3d79380a3192691d6a0baefc [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
AppaRao Pulib52664e2020-04-09 21:36:51 +053017#include "event_service_manager.hpp"
AppaRao Pulie5aaf042020-03-20 01:05:52 +053018
19namespace redfish
20{
21
AppaRao Puli156d6b02020-04-25 06:04:05 +053022static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
23 eventFormatType, metricReportFormatType};
AppaRao Pulie5aaf042020-03-20 01:05:52 +053024static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
25 "Base", "OpenBMC", "Task"};
26static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
27 "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
28
Sunitha Harishe56f2542020-07-22 02:38:59 -050029#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
30static constexpr const std::array<const char*, 2> supportedResourceTypes = {
31 "IBMConfigFile", "Task"};
32#else
33static constexpr const std::array<const char*, 1> supportedResourceTypes = {
34 "Task"};
35#endif
36
AppaRao Pulie5aaf042020-03-20 01:05:52 +053037static constexpr const uint8_t maxNoOfSubscriptions = 20;
38
AppaRao Pulie5aaf042020-03-20 01:05:52 +053039class EventService : public Node
40{
41 public:
42 EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/")
43 {
AppaRao Pulie5aaf042020-03-20 01:05:52 +053044 entityPrivileges = {
45 {boost::beast::http::verb::get, {{"Login"}}},
46 {boost::beast::http::verb::head, {{"Login"}}},
47 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
48 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
49 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
50 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
51 }
52
53 private:
54 void doGet(crow::Response& res, const crow::Request& req,
55 const std::vector<std::string>& params) override
56 {
57 auto asyncResp = std::make_shared<AsyncResp>(res);
58 res.jsonValue = {
59 {"@odata.type", "#EventService.v1_5_0.EventService"},
60 {"Id", "EventService"},
61 {"Name", "Event Service"},
62 {"ServerSentEventUri",
63 "/redfish/v1/EventService/Subscriptions/SSE"},
64 {"Subscriptions",
65 {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
AppaRao Puli0b4bdd92020-04-14 17:57:45 +053066 {"Actions",
67 {{"#EventService.SubmitTestEvent",
68 {{"target", "/redfish/v1/EventService/Actions/"
69 "EventService.SubmitTestEvent"}}}}},
AppaRao Pulie5aaf042020-03-20 01:05:52 +053070 {"@odata.id", "/redfish/v1/EventService"}};
71
AppaRao Puli7d1cc382020-05-16 02:42:22 +053072 const auto& [enabled, retryAttempts, retryTimeoutInterval] =
73 EventServiceManager::getInstance().getEventServiceConfig();
74
75 asyncResp->res.jsonValue["Status"]["State"] =
76 (enabled ? "Enabled" : "Disabled");
77 asyncResp->res.jsonValue["ServiceEnabled"] = enabled;
78 asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053079 asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
AppaRao Puli7d1cc382020-05-16 02:42:22 +053080 retryTimeoutInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053081 asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
82 asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
Sunitha Harishe56f2542020-07-22 02:38:59 -050083 asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
Ayushi Smriti07941a82020-05-21 15:55:34 +053084
85 nlohmann::json supportedSSEFilters = {
86 {"EventFormatType", true}, {"MessageId", true},
87 {"MetricReportDefinition", true}, {"RegistryPrefix", true},
88 {"OriginResource", false}, {"ResourceType", false}};
89
90 asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
91 supportedSSEFilters;
AppaRao Pulie5aaf042020-03-20 01:05:52 +053092 }
93
94 void doPatch(crow::Response& res, const crow::Request& req,
95 const std::vector<std::string>& params) override
96 {
97 auto asyncResp = std::make_shared<AsyncResp>(res);
98
99 std::optional<bool> serviceEnabled;
100 std::optional<uint32_t> retryAttemps;
101 std::optional<uint32_t> retryInterval;
102
103 if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled,
104 "DeliveryRetryAttempts", retryAttemps,
105 "DeliveryRetryIntervalSeconds", retryInterval))
106 {
107 return;
108 }
109
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530110 auto [enabled, retryCount, retryTimeoutInterval] =
111 EventServiceManager::getInstance().getEventServiceConfig();
112
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530113 if (serviceEnabled)
114 {
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530115 enabled = *serviceEnabled;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530116 }
117
118 if (retryAttemps)
119 {
120 // Supported range [1-3]
121 if ((*retryAttemps < 1) || (*retryAttemps > 3))
122 {
123 messages::queryParameterOutOfRange(
124 asyncResp->res, std::to_string(*retryAttemps),
125 "DeliveryRetryAttempts", "[1-3]");
126 }
127 else
128 {
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530129 retryCount = *retryAttemps;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530130 }
131 }
132
133 if (retryInterval)
134 {
135 // Supported range [30 - 180]
136 if ((*retryInterval < 30) || (*retryInterval > 180))
137 {
138 messages::queryParameterOutOfRange(
139 asyncResp->res, std::to_string(*retryInterval),
140 "DeliveryRetryIntervalSeconds", "[30-180]");
141 }
142 else
143 {
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530144 retryTimeoutInterval = *retryInterval;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530145 }
146 }
147
AppaRao Puli7d1cc382020-05-16 02:42:22 +0530148 EventServiceManager::getInstance().setEventServiceConfig(
149 std::make_tuple(enabled, retryCount, retryTimeoutInterval));
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530150 }
151};
152
AppaRao Puli0b4bdd92020-04-14 17:57:45 +0530153class SubmitTestEvent : public Node
154{
155 public:
156 SubmitTestEvent(CrowApp& app) :
157 Node(app,
158 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
159 {
160 entityPrivileges = {
161 {boost::beast::http::verb::get, {{"Login"}}},
162 {boost::beast::http::verb::head, {{"Login"}}},
163 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
164 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
165 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
166 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
167 }
168
169 private:
170 void doPost(crow::Response& res, const crow::Request& req,
171 const std::vector<std::string>& params) override
172 {
173 EventServiceManager::getInstance().sendTestEventLog();
174 res.result(boost::beast::http::status::no_content);
175 res.end();
176 }
177};
178
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530179class EventDestinationCollection : public Node
180{
181 public:
182 EventDestinationCollection(CrowApp& app) :
183 Node(app, "/redfish/v1/EventService/Subscriptions/")
184 {
185 entityPrivileges = {
186 {boost::beast::http::verb::get, {{"Login"}}},
187 {boost::beast::http::verb::head, {{"Login"}}},
188 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
189 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
190 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
191 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
192 }
193
194 private:
195 void doGet(crow::Response& res, const crow::Request& req,
196 const std::vector<std::string>& params) override
197 {
198 auto asyncResp = std::make_shared<AsyncResp>(res);
199
200 res.jsonValue = {
201 {"@odata.type",
202 "#EventDestinationCollection.EventDestinationCollection"},
203 {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
204 {"Name", "Event Destination Collections"}};
205
206 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530207
AppaRao Pulib52664e2020-04-09 21:36:51 +0530208 std::vector<std::string> subscripIds =
209 EventServiceManager::getInstance().getAllIDs();
210 memberArray = nlohmann::json::array();
211 asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
212
213 for (const std::string& id : subscripIds)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530214 {
215 memberArray.push_back(
216 {{"@odata.id",
AppaRao Pulib52664e2020-04-09 21:36:51 +0530217 "/redfish/v1/EventService/Subscriptions/" + id}});
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530218 }
219 }
220
221 void doPost(crow::Response& res, const crow::Request& req,
222 const std::vector<std::string>& params) override
223 {
224 auto asyncResp = std::make_shared<AsyncResp>(res);
225
AppaRao Pulib52664e2020-04-09 21:36:51 +0530226 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
227 maxNoOfSubscriptions)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530228 {
229 messages::eventSubscriptionLimitExceeded(asyncResp->res);
230 return;
231 }
232 std::string destUrl;
233 std::string protocol;
234 std::optional<std::string> context;
235 std::optional<std::string> subscriptionType;
236 std::optional<std::string> eventFormatType;
237 std::optional<std::string> retryPolicy;
238 std::optional<std::vector<std::string>> msgIds;
239 std::optional<std::vector<std::string>> regPrefixes;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500240 std::optional<std::vector<std::string>> resTypes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530241 std::optional<std::vector<nlohmann::json>> headers;
AppaRao Puli144b6312020-08-03 22:23:12 +0530242 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530243
244 if (!json_util::readJson(
245 req, res, "Destination", destUrl, "Context", context,
246 "Protocol", protocol, "SubscriptionType", subscriptionType,
247 "EventFormatType", eventFormatType, "HttpHeaders", headers,
248 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
AppaRao Puli156d6b02020-04-25 06:04:05 +0530249 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
AppaRao Puli144b6312020-08-03 22:23:12 +0530250 mrdJsonArray, "ResourceTypes", resTypes))
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530251 {
252 return;
253 }
254
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530255 // Validate the URL using regex expression
AppaRao Pulib52664e2020-04-09 21:36:51 +0530256 // Format: <protocol>://<host>:<port>/<uri>
257 // protocol: http/https
258 // host: Exclude ' ', ':', '#', '?'
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500259 // port: Empty or numeric value with ':' separator.
AppaRao Pulib52664e2020-04-09 21:36:51 +0530260 // uri: Start with '/' and Exclude '#', ' '
261 // Can include query params(ex: '/event?test=1')
262 // TODO: Need to validate hostname extensively(as per rfc)
263 const std::regex urlRegex(
264 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
265 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
266 std::cmatch match;
267 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530268 {
269 messages::propertyValueFormatError(asyncResp->res, destUrl,
270 "Destination");
271 return;
272 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530273
274 std::string uriProto = std::string(match[1].first, match[1].second);
275 if (uriProto == "http")
276 {
277#ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
278 messages::propertyValueFormatError(asyncResp->res, destUrl,
279 "Destination");
280 return;
281#endif
282 }
283
284 std::string host = std::string(match[2].first, match[2].second);
285 std::string port = std::string(match[3].first, match[3].second);
286 std::string path = std::string(match[4].first, match[4].second);
287 if (port.empty())
288 {
289 if (uriProto == "http")
290 {
291 port = "80";
292 }
293 else
294 {
295 port = "443";
296 }
297 }
298 if (path.empty())
299 {
300 path = "/";
301 }
302
303 std::shared_ptr<Subscription> subValue =
304 std::make_shared<Subscription>(host, port, path, uriProto);
305
306 subValue->destinationUrl = destUrl;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530307
308 if (subscriptionType)
309 {
310 if (*subscriptionType != "RedfishEvent")
311 {
312 messages::propertyValueNotInList(
313 asyncResp->res, *subscriptionType, "SubscriptionType");
314 return;
315 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530316 subValue->subscriptionType = *subscriptionType;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530317 }
318 else
319 {
AppaRao Pulib52664e2020-04-09 21:36:51 +0530320 subValue->subscriptionType = "RedfishEvent"; // Default
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530321 }
322
323 if (protocol != "Redfish")
324 {
325 messages::propertyValueNotInList(asyncResp->res, protocol,
326 "Protocol");
327 return;
328 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530329 subValue->protocol = protocol;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530330
331 if (eventFormatType)
332 {
333 if (std::find(supportedEvtFormatTypes.begin(),
334 supportedEvtFormatTypes.end(),
335 *eventFormatType) == supportedEvtFormatTypes.end())
336 {
337 messages::propertyValueNotInList(
338 asyncResp->res, *eventFormatType, "EventFormatType");
339 return;
340 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530341 subValue->eventFormatType = *eventFormatType;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530342 }
343 else
344 {
345 // If not specified, use default "Event"
AppaRao Pulib52664e2020-04-09 21:36:51 +0530346 subValue->eventFormatType.assign({"Event"});
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530347 }
348
349 if (context)
350 {
AppaRao Pulib52664e2020-04-09 21:36:51 +0530351 subValue->customText = *context;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530352 }
353
354 if (headers)
355 {
AppaRao Pulib52664e2020-04-09 21:36:51 +0530356 subValue->httpHeaders = *headers;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530357 }
358
359 if (regPrefixes)
360 {
361 for (const std::string& it : *regPrefixes)
362 {
363 if (std::find(supportedRegPrefixes.begin(),
364 supportedRegPrefixes.end(),
365 it) == supportedRegPrefixes.end())
366 {
367 messages::propertyValueNotInList(asyncResp->res, it,
368 "RegistryPrefixes");
369 return;
370 }
371 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530372 subValue->registryPrefixes = *regPrefixes;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530373 }
374
Sunitha Harishe56f2542020-07-22 02:38:59 -0500375 if (resTypes)
376 {
377 for (const std::string& it : *resTypes)
378 {
379 if (std::find(supportedResourceTypes.begin(),
380 supportedResourceTypes.end(),
381 it) == supportedResourceTypes.end())
382 {
383 messages::propertyValueNotInList(asyncResp->res, it,
384 "ResourceTypes");
385 return;
386 }
387 }
388 subValue->resourceTypes = *resTypes;
389 }
390
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530391 if (msgIds)
392 {
393 // Do we need to loop-up MessageRegistry and validate
394 // data for authenticity??? Not mandate, i believe.
AppaRao Pulib52664e2020-04-09 21:36:51 +0530395 subValue->registryMsgIds = *msgIds;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530396 }
397
398 if (retryPolicy)
399 {
400 if (std::find(supportedRetryPolicies.begin(),
401 supportedRetryPolicies.end(),
402 *retryPolicy) == supportedRetryPolicies.end())
403 {
404 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
405 "DeliveryRetryPolicy");
406 return;
407 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530408 subValue->retryPolicy = *retryPolicy;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530409 }
410 else
411 {
412 // Default "TerminateAfterRetries"
AppaRao Pulib52664e2020-04-09 21:36:51 +0530413 subValue->retryPolicy = "TerminateAfterRetries";
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530414 }
415
AppaRao Puli144b6312020-08-03 22:23:12 +0530416 if (mrdJsonArray)
AppaRao Puli156d6b02020-04-25 06:04:05 +0530417 {
AppaRao Puli144b6312020-08-03 22:23:12 +0530418 for (nlohmann::json& mrdObj : *mrdJsonArray)
419 {
420 std::string mrdUri;
421 if (json_util::getValueFromJsonObject(mrdObj, "@odata.id",
422 mrdUri))
423 {
424 subValue->metricReportDefinitions.emplace_back(mrdUri);
425 }
426 else
427 {
428 messages::propertyValueFormatError(
429 asyncResp->res, mrdObj.dump(),
430 "MetricReportDefinitions");
431 return;
432 }
433 }
AppaRao Puli156d6b02020-04-25 06:04:05 +0530434 }
435
AppaRao Pulib52664e2020-04-09 21:36:51 +0530436 std::string id =
437 EventServiceManager::getInstance().addSubscription(subValue);
438 if (id.empty())
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530439 {
440 messages::internalError(asyncResp->res);
441 return;
442 }
443
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530444 messages::created(asyncResp->res);
445 asyncResp->res.addHeader(
446 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
447 }
448};
449
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530450class EventServiceSSE : public Node
451{
452 public:
453 EventServiceSSE(CrowApp& app) :
454 Node(app, "/redfish/v1/EventService/Subscriptions/SSE/")
455 {
456 entityPrivileges = {
457 {boost::beast::http::verb::get, {{"ConfigureManager"}}},
458 {boost::beast::http::verb::head, {{"ConfigureManager"}}},
459 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
460 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
461 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
462 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
463 }
464
465 private:
466 void doGet(crow::Response& res, const crow::Request& req,
467 const std::vector<std::string>& params) override
468 {
469 if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
470 maxNoOfSubscriptions)
471 {
472 messages::eventSubscriptionLimitExceeded(res);
473 res.end();
474 return;
475 }
476
477 std::shared_ptr<crow::Request::Adaptor> sseConn =
478 std::make_shared<crow::Request::Adaptor>(std::move(req.socket()));
479 std::shared_ptr<Subscription> subValue =
480 std::make_shared<Subscription>(sseConn);
481
482 // GET on this URI means, Its SSE subscriptionType.
483 subValue->subscriptionType = "SSE";
Ayushi Smriti07941a82020-05-21 15:55:34 +0530484
485 // Default values
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530486 subValue->protocol = "Redfish";
Ayushi Smriti07941a82020-05-21 15:55:34 +0530487 subValue->retryPolicy = "TerminateAfterRetries";
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530488
James Feist5a7e8772020-07-22 09:08:38 -0700489 boost::urls::url_view::params_type::iterator it =
490 req.urlParams.find("$filter");
491 if (it == req.urlParams.end())
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530492 {
493 subValue->eventFormatType = "Event";
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530494 }
James Feist5a7e8772020-07-22 09:08:38 -0700495
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530496 else
497 {
James Feist5a7e8772020-07-22 09:08:38 -0700498 std::string filters = it->value();
Ayushi Smriti07941a82020-05-21 15:55:34 +0530499 // Reading from query params.
500 bool status = readSSEQueryParams(
501 filters, subValue->eventFormatType, subValue->registryMsgIds,
502 subValue->registryPrefixes, subValue->metricReportDefinitions);
503
504 if (!status)
505 {
506 messages::invalidObject(res, filters);
507 return;
508 }
509
510 if (!subValue->eventFormatType.empty())
511 {
512 if (std::find(supportedEvtFormatTypes.begin(),
513 supportedEvtFormatTypes.end(),
514 subValue->eventFormatType) ==
515 supportedEvtFormatTypes.end())
516 {
517 messages::propertyValueNotInList(
518 res, subValue->eventFormatType, "EventFormatType");
519 return;
520 }
521 }
522 else
523 {
524 // If nothing specified, using default "Event"
525 subValue->eventFormatType.assign({"Event"});
526 }
527
528 if (!subValue->registryPrefixes.empty())
529 {
530 for (const std::string& it : subValue->registryPrefixes)
531 {
532 if (std::find(supportedRegPrefixes.begin(),
533 supportedRegPrefixes.end(),
534 it) == supportedRegPrefixes.end())
535 {
536 messages::propertyValueNotInList(res, it,
537 "RegistryPrefixes");
538 return;
539 }
540 }
541 }
AppaRao Puli4bbf2372020-05-15 21:09:54 +0530542 }
543
544 std::string id =
545 EventServiceManager::getInstance().addSubscription(subValue, false);
546 if (id.empty())
547 {
548 messages::internalError(res);
549 res.end();
550 return;
551 }
552 }
553};
554
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530555class EventDestination : public Node
556{
557 public:
558 EventDestination(CrowApp& app) :
559 Node(app, "/redfish/v1/EventService/Subscriptions/<str>/",
560 std::string())
561 {
562 entityPrivileges = {
563 {boost::beast::http::verb::get, {{"Login"}}},
564 {boost::beast::http::verb::head, {{"Login"}}},
565 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
566 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
567 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
568 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
569 }
570
571 private:
572 void doGet(crow::Response& res, const crow::Request& req,
573 const std::vector<std::string>& params) override
574 {
575 auto asyncResp = std::make_shared<AsyncResp>(res);
576 if (params.size() != 1)
577 {
578 messages::internalError(asyncResp->res);
579 return;
580 }
581
AppaRao Pulib52664e2020-04-09 21:36:51 +0530582 std::shared_ptr<Subscription> subValue =
583 EventServiceManager::getInstance().getSubscription(params[0]);
584 if (subValue == nullptr)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530585 {
586 res.result(boost::beast::http::status::not_found);
587 res.end();
588 return;
589 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530590 const std::string& id = params[0];
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530591
592 res.jsonValue = {
593 {"@odata.type", "#EventDestination.v1_7_0.EventDestination"},
594 {"Protocol", "Redfish"}};
595 asyncResp->res.jsonValue["@odata.id"] =
596 "/redfish/v1/EventService/Subscriptions/" + id;
597 asyncResp->res.jsonValue["Id"] = id;
598 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
AppaRao Pulib52664e2020-04-09 21:36:51 +0530599 asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
600 asyncResp->res.jsonValue["Context"] = subValue->customText;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530601 asyncResp->res.jsonValue["SubscriptionType"] =
AppaRao Pulib52664e2020-04-09 21:36:51 +0530602 subValue->subscriptionType;
603 asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders;
604 asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530605 asyncResp->res.jsonValue["RegistryPrefixes"] =
AppaRao Pulib52664e2020-04-09 21:36:51 +0530606 subValue->registryPrefixes;
Sunitha Harishe56f2542020-07-22 02:38:59 -0500607 asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
608
AppaRao Pulib52664e2020-04-09 21:36:51 +0530609 asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
610 asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
AppaRao Puli144b6312020-08-03 22:23:12 +0530611
612 std::vector<nlohmann::json> mrdJsonArray;
613 for (const auto& mdrUri : subValue->metricReportDefinitions)
614 {
615 mrdJsonArray.push_back({{"@odata.id", mdrUri}});
616 }
617 asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530618 }
619
620 void doPatch(crow::Response& res, const crow::Request& req,
621 const std::vector<std::string>& params) override
622 {
623 auto asyncResp = std::make_shared<AsyncResp>(res);
624 if (params.size() != 1)
625 {
626 messages::internalError(asyncResp->res);
627 return;
628 }
629
AppaRao Pulib52664e2020-04-09 21:36:51 +0530630 std::shared_ptr<Subscription> subValue =
631 EventServiceManager::getInstance().getSubscription(params[0]);
632 if (subValue == nullptr)
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530633 {
634 res.result(boost::beast::http::status::not_found);
635 res.end();
636 return;
637 }
638
639 std::optional<std::string> context;
640 std::optional<std::string> retryPolicy;
641 std::optional<std::vector<nlohmann::json>> headers;
642
643 if (!json_util::readJson(req, res, "Context", context,
644 "DeliveryRetryPolicy", retryPolicy,
645 "HttpHeaders", headers))
646 {
647 return;
648 }
649
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530650 if (context)
651 {
AppaRao Pulib52664e2020-04-09 21:36:51 +0530652 subValue->customText = *context;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530653 }
654
655 if (headers)
656 {
AppaRao Pulib52664e2020-04-09 21:36:51 +0530657 subValue->httpHeaders = *headers;
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530658 }
659
660 if (retryPolicy)
661 {
662 if (std::find(supportedRetryPolicies.begin(),
663 supportedRetryPolicies.end(),
664 *retryPolicy) == supportedRetryPolicies.end())
665 {
666 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
667 "DeliveryRetryPolicy");
668 return;
669 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530670 subValue->retryPolicy = *retryPolicy;
Ayushi Smritife44eb02020-05-15 15:24:45 +0530671 subValue->updateRetryPolicy();
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530672 }
673
AppaRao Pulib52664e2020-04-09 21:36:51 +0530674 EventServiceManager::getInstance().updateSubscriptionData();
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530675 }
676
677 void doDelete(crow::Response& res, const crow::Request& req,
678 const std::vector<std::string>& params) override
679 {
680 auto asyncResp = std::make_shared<AsyncResp>(res);
681
682 if (params.size() != 1)
683 {
684 messages::internalError(asyncResp->res);
685 return;
686 }
687
AppaRao Pulib52664e2020-04-09 21:36:51 +0530688 if (!EventServiceManager::getInstance().isSubscriptionExist(params[0]))
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530689 {
690 res.result(boost::beast::http::status::not_found);
691 res.end();
692 return;
693 }
AppaRao Pulib52664e2020-04-09 21:36:51 +0530694 EventServiceManager::getInstance().deleteSubscription(params[0]);
AppaRao Pulie5aaf042020-03-20 01:05:52 +0530695 }
696};
697
698} // namespace redfish