1e5aaf047SAppaRao Puli /* 2e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation 3e5aaf047SAppaRao Puli // 4e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License"); 5e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License. 6e5aaf047SAppaRao Puli // You may obtain a copy of the License at 7e5aaf047SAppaRao Puli // 8e5aaf047SAppaRao Puli // http://www.apache.org/licenses/LICENSE-2.0 9e5aaf047SAppaRao Puli // 10e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software 11e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS, 12e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and 14e5aaf047SAppaRao Puli // limitations under the License. 15e5aaf047SAppaRao Puli */ 16e5aaf047SAppaRao Puli #pragma once 17b52664e2SAppaRao Puli #include "event_service_manager.hpp" 18e5aaf047SAppaRao Puli 197e860f15SJohn Edward Broadbent #include <app.hpp> 20601c71aeSEd Tanous #include <boost/beast/http/fields.hpp> 21eb1c47d3SEd Tanous #include <http/utility.hpp> 22eb1c47d3SEd Tanous #include <logging.hpp> 2345ca1b86SEd Tanous #include <query.hpp> 24ed398213SEd Tanous #include <registries/privilege_registry.hpp> 25ed398213SEd Tanous 261e270c5fSPatrick Williams #include <span> 271e270c5fSPatrick Williams 28e5aaf047SAppaRao Puli namespace redfish 29e5aaf047SAppaRao Puli { 30e5aaf047SAppaRao Puli 31156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 32156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 33e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 34b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 35e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 36e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 37e5aaf047SAppaRao Puli 38e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 39e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 40e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 41e56f254cSSunitha Harish #else 42e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 43e56f254cSSunitha Harish "Task"}; 44e56f254cSSunitha Harish #endif 45e56f254cSSunitha Harish 46e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 47e5aaf047SAppaRao Puli 487e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 49e5aaf047SAppaRao Puli { 507e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 51ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 52002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 53002d39b4SEd Tanous [&app](const crow::Request& req, 54002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 55*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5645ca1b86SEd Tanous { 5745ca1b86SEd Tanous return; 5845ca1b86SEd Tanous } 591476687dSEd Tanous 601476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 611476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 621476687dSEd Tanous "#EventService.v1_5_0.EventService"; 631476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 641476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 651476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 661476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 67002d39b4SEd Tanous asyncResp->res 68002d39b4SEd Tanous .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] = 691476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 70e5aaf047SAppaRao Puli 7128afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 7228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 7328afb49cSJunLin Chen .getEventServiceConfig(); 747d1cc387SAppaRao Puli 757d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7628afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 77002d39b4SEd Tanous asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled; 787e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 7928afb49cSJunLin Chen eventServiceConfig.retryAttempts; 80e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 8128afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 82002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 830fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 840fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8507941a88SAyushi Smriti 8607941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8707941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8807941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8907941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 9007941a88SAyushi Smriti 9107941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 9207941a88SAyushi Smriti supportedSSEFilters; 937e860f15SJohn Edward Broadbent }); 94e5aaf047SAppaRao Puli 957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 96ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 977e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 9845ca1b86SEd Tanous [&app](const crow::Request& req, 9945ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 100*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101e5aaf047SAppaRao Puli { 10245ca1b86SEd Tanous return; 10345ca1b86SEd Tanous } 104e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 105e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 106e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 107e5aaf047SAppaRao Puli 10815ed6780SWilly Tu if (!json_util::readJsonPatch( 1097e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1107e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1117e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 112e5aaf047SAppaRao Puli { 113e5aaf047SAppaRao Puli return; 114e5aaf047SAppaRao Puli } 115e5aaf047SAppaRao Puli 11628afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11828afb49cSJunLin Chen .getEventServiceConfig(); 1197d1cc387SAppaRao Puli 120e5aaf047SAppaRao Puli if (serviceEnabled) 121e5aaf047SAppaRao Puli { 12228afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 123e5aaf047SAppaRao Puli } 124e5aaf047SAppaRao Puli 125e5aaf047SAppaRao Puli if (retryAttemps) 126e5aaf047SAppaRao Puli { 127e5aaf047SAppaRao Puli // Supported range [1-3] 128e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 129e5aaf047SAppaRao Puli { 130e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 131e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 132e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 133e5aaf047SAppaRao Puli } 134e5aaf047SAppaRao Puli else 135e5aaf047SAppaRao Puli { 13628afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 137e5aaf047SAppaRao Puli } 138e5aaf047SAppaRao Puli } 139e5aaf047SAppaRao Puli 140e5aaf047SAppaRao Puli if (retryInterval) 141e5aaf047SAppaRao Puli { 142e5aaf047SAppaRao Puli // Supported range [30 - 180] 143e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 144e5aaf047SAppaRao Puli { 145e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 146e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 147e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 148e5aaf047SAppaRao Puli } 149e5aaf047SAppaRao Puli else 150e5aaf047SAppaRao Puli { 151002d39b4SEd Tanous eventServiceConfig.retryTimeoutInterval = *retryInterval; 152e5aaf047SAppaRao Puli } 153e5aaf047SAppaRao Puli } 154e5aaf047SAppaRao Puli 1557d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15628afb49cSJunLin Chen eventServiceConfig); 1577e860f15SJohn Edward Broadbent }); 1580b4bdd93SAppaRao Puli } 1590b4bdd93SAppaRao Puli 1607e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1610b4bdd93SAppaRao Puli { 1627e860f15SJohn Edward Broadbent 1637e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1647e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 165ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1667e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 16745ca1b86SEd Tanous [&app](const crow::Request& req, 1687e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 169*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17045ca1b86SEd Tanous { 17145ca1b86SEd Tanous return; 17245ca1b86SEd Tanous } 1736ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1746ba8c82eSsunharis_in { 1756ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1766ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1776ba8c82eSsunharis_in return; 1786ba8c82eSsunharis_in } 1798d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1807e860f15SJohn Edward Broadbent }); 181e5aaf047SAppaRao Puli } 182e5aaf047SAppaRao Puli 1837e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 184e5aaf047SAppaRao Puli { 1851ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 186ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 18845ca1b86SEd Tanous [&app](const crow::Request& req, 1897e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 190*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19145ca1b86SEd Tanous { 19245ca1b86SEd Tanous return; 19345ca1b86SEd Tanous } 1941476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 1951476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 1961476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1971476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 198002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Event Destination Collections"; 199e5aaf047SAppaRao Puli 200002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 201e5aaf047SAppaRao Puli 202b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 203b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 204b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 205002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size(); 206b52664e2SAppaRao Puli 207b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 208e5aaf047SAppaRao Puli { 2091476687dSEd Tanous nlohmann::json::object_t member; 2101476687dSEd Tanous member["@odata.id"] = 2111476687dSEd Tanous "/redfish/v1/EventService/Subscriptions/" + id; 2121476687dSEd Tanous memberArray.push_back(std::move(member)); 213e5aaf047SAppaRao Puli } 2147e860f15SJohn Edward Broadbent }); 2157e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2167eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 217002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 218002d39b4SEd Tanous [&app](const crow::Request& req, 2197e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 220*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 22145ca1b86SEd Tanous { 22245ca1b86SEd Tanous return; 22345ca1b86SEd Tanous } 224fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 225fffb8c1fSEd Tanous maxNoOfSubscriptions) 226e5aaf047SAppaRao Puli { 227e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 228e5aaf047SAppaRao Puli return; 229e5aaf047SAppaRao Puli } 230e5aaf047SAppaRao Puli std::string destUrl; 231e5aaf047SAppaRao Puli std::string protocol; 232e5aaf047SAppaRao Puli std::optional<std::string> context; 233e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 23423a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 235e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 236e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 237e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 238e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 239e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 240144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 241e5aaf047SAppaRao Puli 24215ed6780SWilly Tu if (!json_util::readJsonPatch( 243002d39b4SEd Tanous req, asyncResp->res, "Destination", destUrl, "Context", context, 244002d39b4SEd Tanous "Protocol", protocol, "SubscriptionType", subscriptionType, 245002d39b4SEd Tanous "EventFormatType", eventFormatType2, "HttpHeaders", headers, 246002d39b4SEd Tanous "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 247002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 248002d39b4SEd Tanous mrdJsonArray, "ResourceTypes", resTypes)) 249e5aaf047SAppaRao Puli { 250e5aaf047SAppaRao Puli return; 251e5aaf047SAppaRao Puli } 252e5aaf047SAppaRao Puli 253dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 254dd28ba82SAppaRao Puli { 25526f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 256dd28ba82SAppaRao Puli { 257002d39b4SEd Tanous messages::propertyValueConflict(asyncResp->res, "MessageIds", 258002d39b4SEd Tanous "RegistryPrefixes"); 259dd28ba82SAppaRao Puli return; 260dd28ba82SAppaRao Puli } 261dd28ba82SAppaRao Puli } 262dd28ba82SAppaRao Puli 263eb1c47d3SEd Tanous std::string host; 264eb1c47d3SEd Tanous std::string urlProto; 265eb1c47d3SEd Tanous uint16_t port = 0; 266eb1c47d3SEd Tanous std::string path; 267eb1c47d3SEd Tanous 268002d39b4SEd Tanous if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port, 269002d39b4SEd Tanous path)) 270e5aaf047SAppaRao Puli { 271eb1c47d3SEd Tanous BMCWEB_LOG_WARNING 272eb1c47d3SEd Tanous << "Failed to validate and split destination url"; 273e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 274e5aaf047SAppaRao Puli "Destination"); 275e5aaf047SAppaRao Puli return; 276e5aaf047SAppaRao Puli } 277b52664e2SAppaRao Puli 278b52664e2SAppaRao Puli if (path.empty()) 279b52664e2SAppaRao Puli { 280b52664e2SAppaRao Puli path = "/"; 281b52664e2SAppaRao Puli } 282b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 283eb1c47d3SEd Tanous std::make_shared<Subscription>(host, port, path, urlProto); 284b52664e2SAppaRao Puli 285b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 286e5aaf047SAppaRao Puli 287e5aaf047SAppaRao Puli if (subscriptionType) 288e5aaf047SAppaRao Puli { 289e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 290e5aaf047SAppaRao Puli { 291fffb8c1fSEd Tanous messages::propertyValueNotInList( 292fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 293e5aaf047SAppaRao Puli return; 294e5aaf047SAppaRao Puli } 295b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 296e5aaf047SAppaRao Puli } 297e5aaf047SAppaRao Puli else 298e5aaf047SAppaRao Puli { 299b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 300e5aaf047SAppaRao Puli } 301e5aaf047SAppaRao Puli 302e5aaf047SAppaRao Puli if (protocol != "Redfish") 303e5aaf047SAppaRao Puli { 304e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 305e5aaf047SAppaRao Puli "Protocol"); 306e5aaf047SAppaRao Puli return; 307e5aaf047SAppaRao Puli } 308b52664e2SAppaRao Puli subValue->protocol = protocol; 309e5aaf047SAppaRao Puli 31023a21a1cSEd Tanous if (eventFormatType2) 311e5aaf047SAppaRao Puli { 312e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 313e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 314002d39b4SEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 315e5aaf047SAppaRao Puli { 316fffb8c1fSEd Tanous messages::propertyValueNotInList( 317fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 318e5aaf047SAppaRao Puli return; 319e5aaf047SAppaRao Puli } 32023a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 321e5aaf047SAppaRao Puli } 322e5aaf047SAppaRao Puli else 323e5aaf047SAppaRao Puli { 324e5aaf047SAppaRao Puli // If not specified, use default "Event" 32523a21a1cSEd Tanous subValue->eventFormatType = "Event"; 326e5aaf047SAppaRao Puli } 327e5aaf047SAppaRao Puli 328e5aaf047SAppaRao Puli if (context) 329e5aaf047SAppaRao Puli { 330b52664e2SAppaRao Puli subValue->customText = *context; 331e5aaf047SAppaRao Puli } 332e5aaf047SAppaRao Puli 333e5aaf047SAppaRao Puli if (headers) 334e5aaf047SAppaRao Puli { 335601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 336601c71aeSEd Tanous { 337601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 338601c71aeSEd Tanous { 339601c71aeSEd Tanous const std::string* value = 340601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 341601c71aeSEd Tanous if (value == nullptr) 342601c71aeSEd Tanous { 343601c71aeSEd Tanous messages::propertyValueFormatError( 344e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 345601c71aeSEd Tanous "HttpHeaders/" + item.key()); 346601c71aeSEd Tanous return; 347601c71aeSEd Tanous } 348601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 349601c71aeSEd Tanous } 350601c71aeSEd Tanous } 351e5aaf047SAppaRao Puli } 352e5aaf047SAppaRao Puli 353e5aaf047SAppaRao Puli if (regPrefixes) 354e5aaf047SAppaRao Puli { 355e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 356e5aaf047SAppaRao Puli { 357e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 358e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 359e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 360e5aaf047SAppaRao Puli { 361fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 362fffb8c1fSEd Tanous "RegistryPrefixes"); 363e5aaf047SAppaRao Puli return; 364e5aaf047SAppaRao Puli } 365e5aaf047SAppaRao Puli } 366b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 367e5aaf047SAppaRao Puli } 368e5aaf047SAppaRao Puli 369e56f254cSSunitha Harish if (resTypes) 370e56f254cSSunitha Harish { 371e56f254cSSunitha Harish for (const std::string& it : *resTypes) 372e56f254cSSunitha Harish { 373e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 374e56f254cSSunitha Harish supportedResourceTypes.end(), 375e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 376e56f254cSSunitha Harish { 377e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 378e56f254cSSunitha Harish "ResourceTypes"); 379e56f254cSSunitha Harish return; 380e56f254cSSunitha Harish } 381e56f254cSSunitha Harish } 382e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 383e56f254cSSunitha Harish } 384e56f254cSSunitha Harish 385e5aaf047SAppaRao Puli if (msgIds) 386e5aaf047SAppaRao Puli { 387b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 388b304bd79SP Dheeraj Srujan Kumar 3897e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 3907e860f15SJohn Edward Broadbent // supported prefixes 391b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 392b304bd79SP Dheeraj Srujan Kumar { 393b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 394b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 395b304bd79SP Dheeraj Srujan Kumar } 396b304bd79SP Dheeraj Srujan Kumar else 397b304bd79SP Dheeraj Srujan Kumar { 398b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 399b304bd79SP Dheeraj Srujan Kumar } 400b304bd79SP Dheeraj Srujan Kumar 401b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 402b304bd79SP Dheeraj Srujan Kumar { 403b304bd79SP Dheeraj Srujan Kumar bool validId = false; 404b304bd79SP Dheeraj Srujan Kumar 405b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 406b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 407b304bd79SP Dheeraj Srujan Kumar { 408fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 409fffb8c1fSEd Tanous registry = 410fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 411b304bd79SP Dheeraj Srujan Kumar 412b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 41326702d01SEd Tanous registry.begin(), registry.end(), 414fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 415fffb8c1fSEd Tanous messageEntry) { 41655f79e6fSEd Tanous return id == messageEntry.first; 417b304bd79SP Dheeraj Srujan Kumar })) 418b304bd79SP Dheeraj Srujan Kumar { 419b304bd79SP Dheeraj Srujan Kumar validId = true; 420b304bd79SP Dheeraj Srujan Kumar break; 421b304bd79SP Dheeraj Srujan Kumar } 422b304bd79SP Dheeraj Srujan Kumar } 423b304bd79SP Dheeraj Srujan Kumar 424b304bd79SP Dheeraj Srujan Kumar if (!validId) 425b304bd79SP Dheeraj Srujan Kumar { 426b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 427b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 428b304bd79SP Dheeraj Srujan Kumar return; 429b304bd79SP Dheeraj Srujan Kumar } 430b304bd79SP Dheeraj Srujan Kumar } 431b304bd79SP Dheeraj Srujan Kumar 432b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 433e5aaf047SAppaRao Puli } 434e5aaf047SAppaRao Puli 435e5aaf047SAppaRao Puli if (retryPolicy) 436e5aaf047SAppaRao Puli { 437e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 438e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 439e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 440e5aaf047SAppaRao Puli { 441002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 442002d39b4SEd Tanous "DeliveryRetryPolicy"); 443e5aaf047SAppaRao Puli return; 444e5aaf047SAppaRao Puli } 445b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 446e5aaf047SAppaRao Puli } 447e5aaf047SAppaRao Puli else 448e5aaf047SAppaRao Puli { 449e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 450b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 451e5aaf047SAppaRao Puli } 452e5aaf047SAppaRao Puli 453144b6318SAppaRao Puli if (mrdJsonArray) 454156d6b00SAppaRao Puli { 455144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 456144b6318SAppaRao Puli { 457144b6318SAppaRao Puli std::string mrdUri; 458ea2e6eecSWilly Tu 459002d39b4SEd Tanous if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id", 460002d39b4SEd Tanous mrdUri)) 461ea2e6eecSWilly Tu 462144b6318SAppaRao Puli { 463144b6318SAppaRao Puli return; 464144b6318SAppaRao Puli } 465ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 466144b6318SAppaRao Puli } 467156d6b00SAppaRao Puli } 468156d6b00SAppaRao Puli 469b52664e2SAppaRao Puli std::string id = 470fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 471b52664e2SAppaRao Puli if (id.empty()) 472e5aaf047SAppaRao Puli { 473e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 474e5aaf047SAppaRao Puli return; 475e5aaf047SAppaRao Puli } 476e5aaf047SAppaRao Puli 477e5aaf047SAppaRao Puli messages::created(asyncResp->res); 478e5aaf047SAppaRao Puli asyncResp->res.addHeader( 479e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 4807e860f15SJohn Edward Broadbent }); 481e5aaf047SAppaRao Puli } 482e5aaf047SAppaRao Puli 4837e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 484e5aaf047SAppaRao Puli { 4859d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 486ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 4877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 48845ca1b86SEd Tanous [&app](const crow::Request& req, 4897e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4907e860f15SJohn Edward Broadbent const std::string& param) { 491*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49245ca1b86SEd Tanous { 49345ca1b86SEd Tanous return; 49445ca1b86SEd Tanous } 495b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 4967e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 497b52664e2SAppaRao Puli if (subValue == nullptr) 498e5aaf047SAppaRao Puli { 499002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 500e5aaf047SAppaRao Puli return; 501e5aaf047SAppaRao Puli } 5027e860f15SJohn Edward Broadbent const std::string& id = param; 503e5aaf047SAppaRao Puli 5041476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5051476687dSEd Tanous "#EventDestination.v1_7_0.EventDestination"; 5061476687dSEd Tanous asyncResp->res.jsonValue["Protocol"] = "Redfish"; 507e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 508e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 509e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 510e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 511002d39b4SEd Tanous asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 512b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 513e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 514b52664e2SAppaRao Puli subValue->subscriptionType; 515002d39b4SEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array(); 516002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 517e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 518b52664e2SAppaRao Puli subValue->registryPrefixes; 519002d39b4SEd Tanous asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 520e56f254cSSunitha Harish 521002d39b4SEd Tanous asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 522002d39b4SEd Tanous asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 523144b6318SAppaRao Puli 5241476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 525144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 526144b6318SAppaRao Puli { 5271476687dSEd Tanous nlohmann::json::object_t mdr; 5281476687dSEd Tanous mdr["@odata.id"] = mdrUri; 5291476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 530144b6318SAppaRao Puli } 531002d39b4SEd Tanous asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 5327e860f15SJohn Edward Broadbent }); 5339d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 534ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 535ed398213SEd Tanous // ConfigureSelf 5367eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 537ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 538432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5397e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 54045ca1b86SEd Tanous [&app](const crow::Request& req, 5417e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5427e860f15SJohn Edward Broadbent const std::string& param) { 543*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54445ca1b86SEd Tanous { 54545ca1b86SEd Tanous return; 54645ca1b86SEd Tanous } 547b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5487e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 549b52664e2SAppaRao Puli if (subValue == nullptr) 550e5aaf047SAppaRao Puli { 551002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 552e5aaf047SAppaRao Puli return; 553e5aaf047SAppaRao Puli } 554e5aaf047SAppaRao Puli 555e5aaf047SAppaRao Puli std::optional<std::string> context; 556e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 557e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 558e5aaf047SAppaRao Puli 559002d39b4SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context, 560002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, 561002d39b4SEd Tanous "HttpHeaders", headers)) 562e5aaf047SAppaRao Puli { 563e5aaf047SAppaRao Puli return; 564e5aaf047SAppaRao Puli } 565e5aaf047SAppaRao Puli 566e5aaf047SAppaRao Puli if (context) 567e5aaf047SAppaRao Puli { 568b52664e2SAppaRao Puli subValue->customText = *context; 569e5aaf047SAppaRao Puli } 570e5aaf047SAppaRao Puli 571e5aaf047SAppaRao Puli if (headers) 572e5aaf047SAppaRao Puli { 573601c71aeSEd Tanous boost::beast::http::fields fields; 574601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 575601c71aeSEd Tanous { 576601c71aeSEd Tanous for (auto& it : headerChunk.items()) 577601c71aeSEd Tanous { 578601c71aeSEd Tanous const std::string* value = 579601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 580601c71aeSEd Tanous if (value == nullptr) 581601c71aeSEd Tanous { 582601c71aeSEd Tanous messages::propertyValueFormatError( 583002d39b4SEd Tanous asyncResp->res, it.value().dump(2, ' ', true), 584601c71aeSEd Tanous "HttpHeaders/" + it.key()); 585601c71aeSEd Tanous return; 586601c71aeSEd Tanous } 587601c71aeSEd Tanous fields.set(it.key(), *value); 588601c71aeSEd Tanous } 589601c71aeSEd Tanous } 590601c71aeSEd Tanous subValue->httpHeaders = fields; 591e5aaf047SAppaRao Puli } 592e5aaf047SAppaRao Puli 593e5aaf047SAppaRao Puli if (retryPolicy) 594e5aaf047SAppaRao Puli { 595e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 596e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 597e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 598e5aaf047SAppaRao Puli { 599002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 600e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 601e5aaf047SAppaRao Puli return; 602e5aaf047SAppaRao Puli } 603b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 604fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 605e5aaf047SAppaRao Puli } 606e5aaf047SAppaRao Puli 607b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6087e860f15SJohn Edward Broadbent }); 6099d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 610ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 611ed398213SEd Tanous // ConfigureSelf 6127eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 613ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 614432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6157e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 61645ca1b86SEd Tanous [&app](const crow::Request& req, 6177e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6187e860f15SJohn Edward Broadbent const std::string& param) { 619*3ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 62045ca1b86SEd Tanous { 62145ca1b86SEd Tanous return; 62245ca1b86SEd Tanous } 623002d39b4SEd Tanous if (!EventServiceManager::getInstance().isSubscriptionExist(param)) 624e5aaf047SAppaRao Puli { 625002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 626e5aaf047SAppaRao Puli return; 627e5aaf047SAppaRao Puli } 6287e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6297e860f15SJohn Edward Broadbent }); 630e5aaf047SAppaRao Puli } 631e5aaf047SAppaRao Puli 632e5aaf047SAppaRao Puli } // namespace redfish 633