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 173ccb3adbSEd Tanous #include "app.hpp" 18b52664e2SAppaRao Puli #include "event_service_manager.hpp" 193ccb3adbSEd Tanous #include "http/utility.hpp" 203ccb3adbSEd Tanous #include "logging.hpp" 213ccb3adbSEd Tanous #include "query.hpp" 223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 23e5aaf047SAppaRao Puli 24601c71aeSEd Tanous #include <boost/beast/http/fields.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) { 553ba00073SCarson 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 86613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 87613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 88613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 89613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 90613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 91613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 92613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 9307941a88SAyushi Smriti 9407941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 95613dabeaSEd Tanous std::move(supportedSSEFilters); 967e860f15SJohn Edward Broadbent }); 97e5aaf047SAppaRao Puli 987e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 99ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1007e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 10145ca1b86SEd Tanous [&app](const crow::Request& req, 10245ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1033ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 104e5aaf047SAppaRao Puli { 10545ca1b86SEd Tanous return; 10645ca1b86SEd Tanous } 107e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 108e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 109e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 110e5aaf047SAppaRao Puli 11115ed6780SWilly Tu if (!json_util::readJsonPatch( 1127e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1137e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1147e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 115e5aaf047SAppaRao Puli { 116e5aaf047SAppaRao Puli return; 117e5aaf047SAppaRao Puli } 118e5aaf047SAppaRao Puli 11928afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 12028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 12128afb49cSJunLin Chen .getEventServiceConfig(); 1227d1cc387SAppaRao Puli 123e5aaf047SAppaRao Puli if (serviceEnabled) 124e5aaf047SAppaRao Puli { 12528afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 126e5aaf047SAppaRao Puli } 127e5aaf047SAppaRao Puli 128e5aaf047SAppaRao Puli if (retryAttemps) 129e5aaf047SAppaRao Puli { 130e5aaf047SAppaRao Puli // Supported range [1-3] 131e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 132e5aaf047SAppaRao Puli { 133e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 134e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 135e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 136e5aaf047SAppaRao Puli } 137e5aaf047SAppaRao Puli else 138e5aaf047SAppaRao Puli { 13928afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 140e5aaf047SAppaRao Puli } 141e5aaf047SAppaRao Puli } 142e5aaf047SAppaRao Puli 143e5aaf047SAppaRao Puli if (retryInterval) 144e5aaf047SAppaRao Puli { 14533a32b34SGunnar Mills // Supported range [5 - 180] 14633a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 147e5aaf047SAppaRao Puli { 148e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 149e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 15033a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 151e5aaf047SAppaRao Puli } 152e5aaf047SAppaRao Puli else 153e5aaf047SAppaRao Puli { 154002d39b4SEd Tanous eventServiceConfig.retryTimeoutInterval = *retryInterval; 155e5aaf047SAppaRao Puli } 156e5aaf047SAppaRao Puli } 157e5aaf047SAppaRao Puli 1587d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15928afb49cSJunLin Chen eventServiceConfig); 1607e860f15SJohn Edward Broadbent }); 1610b4bdd93SAppaRao Puli } 1620b4bdd93SAppaRao Puli 1637e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1640b4bdd93SAppaRao Puli { 1657e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1667e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 167ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1687e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 16945ca1b86SEd Tanous [&app](const crow::Request& req, 1707e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17245ca1b86SEd Tanous { 17345ca1b86SEd Tanous return; 17445ca1b86SEd Tanous } 1756ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1766ba8c82eSsunharis_in { 1776ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1786ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1796ba8c82eSsunharis_in return; 1806ba8c82eSsunharis_in } 1818d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1827e860f15SJohn Edward Broadbent }); 183e5aaf047SAppaRao Puli } 184e5aaf047SAppaRao Puli 1857e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 186e5aaf047SAppaRao Puli { 1871ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 188ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1897e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 19045ca1b86SEd Tanous [&app](const crow::Request& req, 1917e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19345ca1b86SEd Tanous { 19445ca1b86SEd Tanous return; 19545ca1b86SEd Tanous } 1961476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 1971476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 1981476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1991476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 200002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Event Destination Collections"; 201e5aaf047SAppaRao Puli 202002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 203e5aaf047SAppaRao Puli 204b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 205b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 206b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 207002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size(); 208b52664e2SAppaRao Puli 209b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 210e5aaf047SAppaRao Puli { 2111476687dSEd Tanous nlohmann::json::object_t member; 21289492a15SPatrick Williams member["@odata.id"] = "/redfish/v1/EventService/Subscriptions/" + 21389492a15SPatrick Williams id; 214*b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 215e5aaf047SAppaRao Puli } 2167e860f15SJohn Edward Broadbent }); 2177e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2187eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 219002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 220002d39b4SEd Tanous [&app](const crow::Request& req, 2217e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 22345ca1b86SEd Tanous { 22445ca1b86SEd Tanous return; 22545ca1b86SEd Tanous } 226fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 227fffb8c1fSEd Tanous maxNoOfSubscriptions) 228e5aaf047SAppaRao Puli { 229e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 230e5aaf047SAppaRao Puli return; 231e5aaf047SAppaRao Puli } 232e5aaf047SAppaRao Puli std::string destUrl; 233e5aaf047SAppaRao Puli std::string protocol; 234e5aaf047SAppaRao Puli std::optional<std::string> context; 235e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 23623a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 237e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 238e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 239e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 240e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 241e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 242144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 243e5aaf047SAppaRao Puli 24415ed6780SWilly Tu if (!json_util::readJsonPatch( 245002d39b4SEd Tanous req, asyncResp->res, "Destination", destUrl, "Context", context, 246002d39b4SEd Tanous "Protocol", protocol, "SubscriptionType", subscriptionType, 247002d39b4SEd Tanous "EventFormatType", eventFormatType2, "HttpHeaders", headers, 248002d39b4SEd Tanous "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 249002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 250002d39b4SEd Tanous mrdJsonArray, "ResourceTypes", resTypes)) 251e5aaf047SAppaRao Puli { 252e5aaf047SAppaRao Puli return; 253e5aaf047SAppaRao Puli } 254e5aaf047SAppaRao Puli 255dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 256dd28ba82SAppaRao Puli { 25726f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 258dd28ba82SAppaRao Puli { 259002d39b4SEd Tanous messages::propertyValueConflict(asyncResp->res, "MessageIds", 260002d39b4SEd Tanous "RegistryPrefixes"); 261dd28ba82SAppaRao Puli return; 262dd28ba82SAppaRao Puli } 263dd28ba82SAppaRao Puli } 264dd28ba82SAppaRao Puli 265eb1c47d3SEd Tanous std::string host; 266eb1c47d3SEd Tanous std::string urlProto; 267eb1c47d3SEd Tanous uint16_t port = 0; 268eb1c47d3SEd Tanous std::string path; 269eb1c47d3SEd Tanous 270002d39b4SEd Tanous if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port, 271002d39b4SEd Tanous path)) 272e5aaf047SAppaRao Puli { 273eb1c47d3SEd Tanous BMCWEB_LOG_WARNING 274eb1c47d3SEd Tanous << "Failed to validate and split destination url"; 275e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 276e5aaf047SAppaRao Puli "Destination"); 277e5aaf047SAppaRao Puli return; 278e5aaf047SAppaRao Puli } 279b52664e2SAppaRao Puli 280b52664e2SAppaRao Puli if (path.empty()) 281b52664e2SAppaRao Puli { 282b52664e2SAppaRao Puli path = "/"; 283b52664e2SAppaRao Puli } 284b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 285eb1c47d3SEd Tanous std::make_shared<Subscription>(host, port, path, urlProto); 286b52664e2SAppaRao Puli 287b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 288e5aaf047SAppaRao Puli 289e5aaf047SAppaRao Puli if (subscriptionType) 290e5aaf047SAppaRao Puli { 291e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 292e5aaf047SAppaRao Puli { 293fffb8c1fSEd Tanous messages::propertyValueNotInList( 294fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 295e5aaf047SAppaRao Puli return; 296e5aaf047SAppaRao Puli } 297b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 298e5aaf047SAppaRao Puli } 299e5aaf047SAppaRao Puli else 300e5aaf047SAppaRao Puli { 301b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 302e5aaf047SAppaRao Puli } 303e5aaf047SAppaRao Puli 304e5aaf047SAppaRao Puli if (protocol != "Redfish") 305e5aaf047SAppaRao Puli { 306e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 307e5aaf047SAppaRao Puli "Protocol"); 308e5aaf047SAppaRao Puli return; 309e5aaf047SAppaRao Puli } 310b52664e2SAppaRao Puli subValue->protocol = protocol; 311e5aaf047SAppaRao Puli 31223a21a1cSEd Tanous if (eventFormatType2) 313e5aaf047SAppaRao Puli { 314e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 315e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 316002d39b4SEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 317e5aaf047SAppaRao Puli { 318fffb8c1fSEd Tanous messages::propertyValueNotInList( 319fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 320e5aaf047SAppaRao Puli return; 321e5aaf047SAppaRao Puli } 32223a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 323e5aaf047SAppaRao Puli } 324e5aaf047SAppaRao Puli else 325e5aaf047SAppaRao Puli { 326e5aaf047SAppaRao Puli // If not specified, use default "Event" 32723a21a1cSEd Tanous subValue->eventFormatType = "Event"; 328e5aaf047SAppaRao Puli } 329e5aaf047SAppaRao Puli 330e5aaf047SAppaRao Puli if (context) 331e5aaf047SAppaRao Puli { 332b52664e2SAppaRao Puli subValue->customText = *context; 333e5aaf047SAppaRao Puli } 334e5aaf047SAppaRao Puli 335e5aaf047SAppaRao Puli if (headers) 336e5aaf047SAppaRao Puli { 337601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 338601c71aeSEd Tanous { 339601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 340601c71aeSEd Tanous { 341601c71aeSEd Tanous const std::string* value = 342601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 343601c71aeSEd Tanous if (value == nullptr) 344601c71aeSEd Tanous { 345601c71aeSEd Tanous messages::propertyValueFormatError( 346e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 347601c71aeSEd Tanous "HttpHeaders/" + item.key()); 348601c71aeSEd Tanous return; 349601c71aeSEd Tanous } 350601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 351601c71aeSEd Tanous } 352601c71aeSEd Tanous } 353e5aaf047SAppaRao Puli } 354e5aaf047SAppaRao Puli 355e5aaf047SAppaRao Puli if (regPrefixes) 356e5aaf047SAppaRao Puli { 357e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 358e5aaf047SAppaRao Puli { 359e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 360e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 361e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 362e5aaf047SAppaRao Puli { 363fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 364fffb8c1fSEd Tanous "RegistryPrefixes"); 365e5aaf047SAppaRao Puli return; 366e5aaf047SAppaRao Puli } 367e5aaf047SAppaRao Puli } 368b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 369e5aaf047SAppaRao Puli } 370e5aaf047SAppaRao Puli 371e56f254cSSunitha Harish if (resTypes) 372e56f254cSSunitha Harish { 373e56f254cSSunitha Harish for (const std::string& it : *resTypes) 374e56f254cSSunitha Harish { 375e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 376e56f254cSSunitha Harish supportedResourceTypes.end(), 377e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 378e56f254cSSunitha Harish { 379e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 380e56f254cSSunitha Harish "ResourceTypes"); 381e56f254cSSunitha Harish return; 382e56f254cSSunitha Harish } 383e56f254cSSunitha Harish } 384e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 385e56f254cSSunitha Harish } 386e56f254cSSunitha Harish 387e5aaf047SAppaRao Puli if (msgIds) 388e5aaf047SAppaRao Puli { 389b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 390b304bd79SP Dheeraj Srujan Kumar 3917e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 3927e860f15SJohn Edward Broadbent // supported prefixes 393b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 394b304bd79SP Dheeraj Srujan Kumar { 395b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 396b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 397b304bd79SP Dheeraj Srujan Kumar } 398b304bd79SP Dheeraj Srujan Kumar else 399b304bd79SP Dheeraj Srujan Kumar { 400b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 401b304bd79SP Dheeraj Srujan Kumar } 402b304bd79SP Dheeraj Srujan Kumar 403b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 404b304bd79SP Dheeraj Srujan Kumar { 405b304bd79SP Dheeraj Srujan Kumar bool validId = false; 406b304bd79SP Dheeraj Srujan Kumar 407b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 408b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 409b304bd79SP Dheeraj Srujan Kumar { 410fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 411fffb8c1fSEd Tanous registry = 412fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 413b304bd79SP Dheeraj Srujan Kumar 414b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 41526702d01SEd Tanous registry.begin(), registry.end(), 416fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 417fffb8c1fSEd Tanous messageEntry) { 41855f79e6fSEd Tanous return id == messageEntry.first; 419b304bd79SP Dheeraj Srujan Kumar })) 420b304bd79SP Dheeraj Srujan Kumar { 421b304bd79SP Dheeraj Srujan Kumar validId = true; 422b304bd79SP Dheeraj Srujan Kumar break; 423b304bd79SP Dheeraj Srujan Kumar } 424b304bd79SP Dheeraj Srujan Kumar } 425b304bd79SP Dheeraj Srujan Kumar 426b304bd79SP Dheeraj Srujan Kumar if (!validId) 427b304bd79SP Dheeraj Srujan Kumar { 428b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 429b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 430b304bd79SP Dheeraj Srujan Kumar return; 431b304bd79SP Dheeraj Srujan Kumar } 432b304bd79SP Dheeraj Srujan Kumar } 433b304bd79SP Dheeraj Srujan Kumar 434b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 435e5aaf047SAppaRao Puli } 436e5aaf047SAppaRao Puli 437e5aaf047SAppaRao Puli if (retryPolicy) 438e5aaf047SAppaRao Puli { 439e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 440e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 441e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 442e5aaf047SAppaRao Puli { 443002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 444002d39b4SEd Tanous "DeliveryRetryPolicy"); 445e5aaf047SAppaRao Puli return; 446e5aaf047SAppaRao Puli } 447b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 448e5aaf047SAppaRao Puli } 449e5aaf047SAppaRao Puli else 450e5aaf047SAppaRao Puli { 451e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 452b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 453e5aaf047SAppaRao Puli } 454e5aaf047SAppaRao Puli 455144b6318SAppaRao Puli if (mrdJsonArray) 456156d6b00SAppaRao Puli { 457144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 458144b6318SAppaRao Puli { 459144b6318SAppaRao Puli std::string mrdUri; 460ea2e6eecSWilly Tu 461002d39b4SEd Tanous if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id", 462002d39b4SEd Tanous mrdUri)) 463ea2e6eecSWilly Tu 464144b6318SAppaRao Puli { 465144b6318SAppaRao Puli return; 466144b6318SAppaRao Puli } 467ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 468144b6318SAppaRao Puli } 469156d6b00SAppaRao Puli } 470156d6b00SAppaRao Puli 471b52664e2SAppaRao Puli std::string id = 472fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 473b52664e2SAppaRao Puli if (id.empty()) 474e5aaf047SAppaRao Puli { 475e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 476e5aaf047SAppaRao Puli return; 477e5aaf047SAppaRao Puli } 478e5aaf047SAppaRao Puli 479e5aaf047SAppaRao Puli messages::created(asyncResp->res); 480e5aaf047SAppaRao Puli asyncResp->res.addHeader( 481e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 4827e860f15SJohn Edward Broadbent }); 483e5aaf047SAppaRao Puli } 484e5aaf047SAppaRao Puli 4857e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 486e5aaf047SAppaRao Puli { 4879d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 488ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 4897e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 49045ca1b86SEd Tanous [&app](const crow::Request& req, 4917e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4927e860f15SJohn Edward Broadbent const std::string& param) { 4933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49445ca1b86SEd Tanous { 49545ca1b86SEd Tanous return; 49645ca1b86SEd Tanous } 497b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 4987e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 499b52664e2SAppaRao Puli if (subValue == nullptr) 500e5aaf047SAppaRao Puli { 501002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 502e5aaf047SAppaRao Puli return; 503e5aaf047SAppaRao Puli } 5047e860f15SJohn Edward Broadbent const std::string& id = param; 505e5aaf047SAppaRao Puli 5061476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5071476687dSEd Tanous "#EventDestination.v1_7_0.EventDestination"; 5081476687dSEd Tanous asyncResp->res.jsonValue["Protocol"] = "Redfish"; 509e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 510e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 511e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 512e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 513002d39b4SEd Tanous asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 514b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 515e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 516b52664e2SAppaRao Puli subValue->subscriptionType; 517002d39b4SEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array(); 518002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 519e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 520b52664e2SAppaRao Puli subValue->registryPrefixes; 521002d39b4SEd Tanous asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 522e56f254cSSunitha Harish 523002d39b4SEd Tanous asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 524002d39b4SEd Tanous asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 525144b6318SAppaRao Puli 5261476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 527144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 528144b6318SAppaRao Puli { 5291476687dSEd Tanous nlohmann::json::object_t mdr; 5301476687dSEd Tanous mdr["@odata.id"] = mdrUri; 5311476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 532144b6318SAppaRao Puli } 533002d39b4SEd Tanous asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 5347e860f15SJohn Edward Broadbent }); 5359d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 536ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 537ed398213SEd Tanous // ConfigureSelf 5387eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 539ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 540432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5417e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 54245ca1b86SEd Tanous [&app](const crow::Request& req, 5437e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5447e860f15SJohn Edward Broadbent const std::string& param) { 5453ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54645ca1b86SEd Tanous { 54745ca1b86SEd Tanous return; 54845ca1b86SEd Tanous } 549b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5507e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 551b52664e2SAppaRao Puli if (subValue == nullptr) 552e5aaf047SAppaRao Puli { 553002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 554e5aaf047SAppaRao Puli return; 555e5aaf047SAppaRao Puli } 556e5aaf047SAppaRao Puli 557e5aaf047SAppaRao Puli std::optional<std::string> context; 558e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 559e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 560e5aaf047SAppaRao Puli 561002d39b4SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context, 562002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, 563002d39b4SEd Tanous "HttpHeaders", headers)) 564e5aaf047SAppaRao Puli { 565e5aaf047SAppaRao Puli return; 566e5aaf047SAppaRao Puli } 567e5aaf047SAppaRao Puli 568e5aaf047SAppaRao Puli if (context) 569e5aaf047SAppaRao Puli { 570b52664e2SAppaRao Puli subValue->customText = *context; 571e5aaf047SAppaRao Puli } 572e5aaf047SAppaRao Puli 573e5aaf047SAppaRao Puli if (headers) 574e5aaf047SAppaRao Puli { 575601c71aeSEd Tanous boost::beast::http::fields fields; 576601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 577601c71aeSEd Tanous { 57862bafc01SPatrick Williams for (const auto& it : headerChunk.items()) 579601c71aeSEd Tanous { 580601c71aeSEd Tanous const std::string* value = 581601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 582601c71aeSEd Tanous if (value == nullptr) 583601c71aeSEd Tanous { 584601c71aeSEd Tanous messages::propertyValueFormatError( 585002d39b4SEd Tanous asyncResp->res, it.value().dump(2, ' ', true), 586601c71aeSEd Tanous "HttpHeaders/" + it.key()); 587601c71aeSEd Tanous return; 588601c71aeSEd Tanous } 589601c71aeSEd Tanous fields.set(it.key(), *value); 590601c71aeSEd Tanous } 591601c71aeSEd Tanous } 592601c71aeSEd Tanous subValue->httpHeaders = fields; 593e5aaf047SAppaRao Puli } 594e5aaf047SAppaRao Puli 595e5aaf047SAppaRao Puli if (retryPolicy) 596e5aaf047SAppaRao Puli { 597e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 598e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 599e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 600e5aaf047SAppaRao Puli { 601002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 602e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 603e5aaf047SAppaRao Puli return; 604e5aaf047SAppaRao Puli } 605b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 606e5aaf047SAppaRao Puli } 607e5aaf047SAppaRao Puli 608b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6097e860f15SJohn Edward Broadbent }); 6109d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 611ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 612ed398213SEd Tanous // ConfigureSelf 6137eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 614ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 615432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6167e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 61745ca1b86SEd Tanous [&app](const crow::Request& req, 6187e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6197e860f15SJohn Edward Broadbent const std::string& param) { 6203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 62145ca1b86SEd Tanous { 62245ca1b86SEd Tanous return; 62345ca1b86SEd Tanous } 624002d39b4SEd Tanous if (!EventServiceManager::getInstance().isSubscriptionExist(param)) 625e5aaf047SAppaRao Puli { 626002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 627e5aaf047SAppaRao Puli return; 628e5aaf047SAppaRao Puli } 6297e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6307e860f15SJohn Edward Broadbent }); 631e5aaf047SAppaRao Puli } 632e5aaf047SAppaRao Puli 633e5aaf047SAppaRao Puli } // namespace redfish 634