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) { 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 { 145*33a32b34SGunnar Mills // Supported range [5 - 180] 146*33a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 147e5aaf047SAppaRao Puli { 148e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 149e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 150*33a32b34SGunnar 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 1667e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1677e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 168ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 17045ca1b86SEd Tanous [&app](const crow::Request& req, 1717e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17345ca1b86SEd Tanous { 17445ca1b86SEd Tanous return; 17545ca1b86SEd Tanous } 1766ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1776ba8c82eSsunharis_in { 1786ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1796ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1806ba8c82eSsunharis_in return; 1816ba8c82eSsunharis_in } 1828d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1837e860f15SJohn Edward Broadbent }); 184e5aaf047SAppaRao Puli } 185e5aaf047SAppaRao Puli 1867e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 187e5aaf047SAppaRao Puli { 1881ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 189ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1907e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 19145ca1b86SEd Tanous [&app](const crow::Request& req, 1927e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19445ca1b86SEd Tanous { 19545ca1b86SEd Tanous return; 19645ca1b86SEd Tanous } 1971476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 1981476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 1991476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2001476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 201002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Event Destination Collections"; 202e5aaf047SAppaRao Puli 203002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 204e5aaf047SAppaRao Puli 205b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 206b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 207b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 208002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size(); 209b52664e2SAppaRao Puli 210b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 211e5aaf047SAppaRao Puli { 2121476687dSEd Tanous nlohmann::json::object_t member; 2131476687dSEd Tanous member["@odata.id"] = 2141476687dSEd Tanous "/redfish/v1/EventService/Subscriptions/" + id; 2151476687dSEd Tanous memberArray.push_back(std::move(member)); 216e5aaf047SAppaRao Puli } 2177e860f15SJohn Edward Broadbent }); 2187e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2197eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 220002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 221002d39b4SEd Tanous [&app](const crow::Request& req, 2227e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 22445ca1b86SEd Tanous { 22545ca1b86SEd Tanous return; 22645ca1b86SEd Tanous } 227fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 228fffb8c1fSEd Tanous maxNoOfSubscriptions) 229e5aaf047SAppaRao Puli { 230e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 231e5aaf047SAppaRao Puli return; 232e5aaf047SAppaRao Puli } 233e5aaf047SAppaRao Puli std::string destUrl; 234e5aaf047SAppaRao Puli std::string protocol; 235e5aaf047SAppaRao Puli std::optional<std::string> context; 236e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 23723a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 238e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 239e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 240e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 241e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 242e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 243144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 244e5aaf047SAppaRao Puli 24515ed6780SWilly Tu if (!json_util::readJsonPatch( 246002d39b4SEd Tanous req, asyncResp->res, "Destination", destUrl, "Context", context, 247002d39b4SEd Tanous "Protocol", protocol, "SubscriptionType", subscriptionType, 248002d39b4SEd Tanous "EventFormatType", eventFormatType2, "HttpHeaders", headers, 249002d39b4SEd Tanous "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 250002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 251002d39b4SEd Tanous mrdJsonArray, "ResourceTypes", resTypes)) 252e5aaf047SAppaRao Puli { 253e5aaf047SAppaRao Puli return; 254e5aaf047SAppaRao Puli } 255e5aaf047SAppaRao Puli 256dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 257dd28ba82SAppaRao Puli { 25826f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 259dd28ba82SAppaRao Puli { 260002d39b4SEd Tanous messages::propertyValueConflict(asyncResp->res, "MessageIds", 261002d39b4SEd Tanous "RegistryPrefixes"); 262dd28ba82SAppaRao Puli return; 263dd28ba82SAppaRao Puli } 264dd28ba82SAppaRao Puli } 265dd28ba82SAppaRao Puli 266eb1c47d3SEd Tanous std::string host; 267eb1c47d3SEd Tanous std::string urlProto; 268eb1c47d3SEd Tanous uint16_t port = 0; 269eb1c47d3SEd Tanous std::string path; 270eb1c47d3SEd Tanous 271002d39b4SEd Tanous if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port, 272002d39b4SEd Tanous path)) 273e5aaf047SAppaRao Puli { 274eb1c47d3SEd Tanous BMCWEB_LOG_WARNING 275eb1c47d3SEd Tanous << "Failed to validate and split destination url"; 276e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 277e5aaf047SAppaRao Puli "Destination"); 278e5aaf047SAppaRao Puli return; 279e5aaf047SAppaRao Puli } 280b52664e2SAppaRao Puli 281b52664e2SAppaRao Puli if (path.empty()) 282b52664e2SAppaRao Puli { 283b52664e2SAppaRao Puli path = "/"; 284b52664e2SAppaRao Puli } 285b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 286eb1c47d3SEd Tanous std::make_shared<Subscription>(host, port, path, urlProto); 287b52664e2SAppaRao Puli 288b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 289e5aaf047SAppaRao Puli 290e5aaf047SAppaRao Puli if (subscriptionType) 291e5aaf047SAppaRao Puli { 292e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 293e5aaf047SAppaRao Puli { 294fffb8c1fSEd Tanous messages::propertyValueNotInList( 295fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 296e5aaf047SAppaRao Puli return; 297e5aaf047SAppaRao Puli } 298b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 299e5aaf047SAppaRao Puli } 300e5aaf047SAppaRao Puli else 301e5aaf047SAppaRao Puli { 302b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 303e5aaf047SAppaRao Puli } 304e5aaf047SAppaRao Puli 305e5aaf047SAppaRao Puli if (protocol != "Redfish") 306e5aaf047SAppaRao Puli { 307e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 308e5aaf047SAppaRao Puli "Protocol"); 309e5aaf047SAppaRao Puli return; 310e5aaf047SAppaRao Puli } 311b52664e2SAppaRao Puli subValue->protocol = protocol; 312e5aaf047SAppaRao Puli 31323a21a1cSEd Tanous if (eventFormatType2) 314e5aaf047SAppaRao Puli { 315e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 316e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 317002d39b4SEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 318e5aaf047SAppaRao Puli { 319fffb8c1fSEd Tanous messages::propertyValueNotInList( 320fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 321e5aaf047SAppaRao Puli return; 322e5aaf047SAppaRao Puli } 32323a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 324e5aaf047SAppaRao Puli } 325e5aaf047SAppaRao Puli else 326e5aaf047SAppaRao Puli { 327e5aaf047SAppaRao Puli // If not specified, use default "Event" 32823a21a1cSEd Tanous subValue->eventFormatType = "Event"; 329e5aaf047SAppaRao Puli } 330e5aaf047SAppaRao Puli 331e5aaf047SAppaRao Puli if (context) 332e5aaf047SAppaRao Puli { 333b52664e2SAppaRao Puli subValue->customText = *context; 334e5aaf047SAppaRao Puli } 335e5aaf047SAppaRao Puli 336e5aaf047SAppaRao Puli if (headers) 337e5aaf047SAppaRao Puli { 338601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 339601c71aeSEd Tanous { 340601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 341601c71aeSEd Tanous { 342601c71aeSEd Tanous const std::string* value = 343601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 344601c71aeSEd Tanous if (value == nullptr) 345601c71aeSEd Tanous { 346601c71aeSEd Tanous messages::propertyValueFormatError( 347e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 348601c71aeSEd Tanous "HttpHeaders/" + item.key()); 349601c71aeSEd Tanous return; 350601c71aeSEd Tanous } 351601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 352601c71aeSEd Tanous } 353601c71aeSEd Tanous } 354e5aaf047SAppaRao Puli } 355e5aaf047SAppaRao Puli 356e5aaf047SAppaRao Puli if (regPrefixes) 357e5aaf047SAppaRao Puli { 358e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 359e5aaf047SAppaRao Puli { 360e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 361e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 362e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 363e5aaf047SAppaRao Puli { 364fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 365fffb8c1fSEd Tanous "RegistryPrefixes"); 366e5aaf047SAppaRao Puli return; 367e5aaf047SAppaRao Puli } 368e5aaf047SAppaRao Puli } 369b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 370e5aaf047SAppaRao Puli } 371e5aaf047SAppaRao Puli 372e56f254cSSunitha Harish if (resTypes) 373e56f254cSSunitha Harish { 374e56f254cSSunitha Harish for (const std::string& it : *resTypes) 375e56f254cSSunitha Harish { 376e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 377e56f254cSSunitha Harish supportedResourceTypes.end(), 378e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 379e56f254cSSunitha Harish { 380e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 381e56f254cSSunitha Harish "ResourceTypes"); 382e56f254cSSunitha Harish return; 383e56f254cSSunitha Harish } 384e56f254cSSunitha Harish } 385e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 386e56f254cSSunitha Harish } 387e56f254cSSunitha Harish 388e5aaf047SAppaRao Puli if (msgIds) 389e5aaf047SAppaRao Puli { 390b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 391b304bd79SP Dheeraj Srujan Kumar 3927e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 3937e860f15SJohn Edward Broadbent // supported prefixes 394b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 395b304bd79SP Dheeraj Srujan Kumar { 396b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 397b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 398b304bd79SP Dheeraj Srujan Kumar } 399b304bd79SP Dheeraj Srujan Kumar else 400b304bd79SP Dheeraj Srujan Kumar { 401b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 402b304bd79SP Dheeraj Srujan Kumar } 403b304bd79SP Dheeraj Srujan Kumar 404b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 405b304bd79SP Dheeraj Srujan Kumar { 406b304bd79SP Dheeraj Srujan Kumar bool validId = false; 407b304bd79SP Dheeraj Srujan Kumar 408b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 409b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 410b304bd79SP Dheeraj Srujan Kumar { 411fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 412fffb8c1fSEd Tanous registry = 413fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 414b304bd79SP Dheeraj Srujan Kumar 415b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 41626702d01SEd Tanous registry.begin(), registry.end(), 417fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 418fffb8c1fSEd Tanous messageEntry) { 41955f79e6fSEd Tanous return id == messageEntry.first; 420b304bd79SP Dheeraj Srujan Kumar })) 421b304bd79SP Dheeraj Srujan Kumar { 422b304bd79SP Dheeraj Srujan Kumar validId = true; 423b304bd79SP Dheeraj Srujan Kumar break; 424b304bd79SP Dheeraj Srujan Kumar } 425b304bd79SP Dheeraj Srujan Kumar } 426b304bd79SP Dheeraj Srujan Kumar 427b304bd79SP Dheeraj Srujan Kumar if (!validId) 428b304bd79SP Dheeraj Srujan Kumar { 429b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 430b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 431b304bd79SP Dheeraj Srujan Kumar return; 432b304bd79SP Dheeraj Srujan Kumar } 433b304bd79SP Dheeraj Srujan Kumar } 434b304bd79SP Dheeraj Srujan Kumar 435b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 436e5aaf047SAppaRao Puli } 437e5aaf047SAppaRao Puli 438e5aaf047SAppaRao Puli if (retryPolicy) 439e5aaf047SAppaRao Puli { 440e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 441e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 442e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 443e5aaf047SAppaRao Puli { 444002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 445002d39b4SEd Tanous "DeliveryRetryPolicy"); 446e5aaf047SAppaRao Puli return; 447e5aaf047SAppaRao Puli } 448b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 449e5aaf047SAppaRao Puli } 450e5aaf047SAppaRao Puli else 451e5aaf047SAppaRao Puli { 452e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 453b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 454e5aaf047SAppaRao Puli } 455e5aaf047SAppaRao Puli 456144b6318SAppaRao Puli if (mrdJsonArray) 457156d6b00SAppaRao Puli { 458144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 459144b6318SAppaRao Puli { 460144b6318SAppaRao Puli std::string mrdUri; 461ea2e6eecSWilly Tu 462002d39b4SEd Tanous if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id", 463002d39b4SEd Tanous mrdUri)) 464ea2e6eecSWilly Tu 465144b6318SAppaRao Puli { 466144b6318SAppaRao Puli return; 467144b6318SAppaRao Puli } 468ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 469144b6318SAppaRao Puli } 470156d6b00SAppaRao Puli } 471156d6b00SAppaRao Puli 472b52664e2SAppaRao Puli std::string id = 473fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 474b52664e2SAppaRao Puli if (id.empty()) 475e5aaf047SAppaRao Puli { 476e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 477e5aaf047SAppaRao Puli return; 478e5aaf047SAppaRao Puli } 479e5aaf047SAppaRao Puli 480e5aaf047SAppaRao Puli messages::created(asyncResp->res); 481e5aaf047SAppaRao Puli asyncResp->res.addHeader( 482e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 4837e860f15SJohn Edward Broadbent }); 484e5aaf047SAppaRao Puli } 485e5aaf047SAppaRao Puli 4867e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 487e5aaf047SAppaRao Puli { 4889d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 489ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 4907e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 49145ca1b86SEd Tanous [&app](const crow::Request& req, 4927e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4937e860f15SJohn Edward Broadbent const std::string& param) { 4943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49545ca1b86SEd Tanous { 49645ca1b86SEd Tanous return; 49745ca1b86SEd Tanous } 498b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 4997e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 500b52664e2SAppaRao Puli if (subValue == nullptr) 501e5aaf047SAppaRao Puli { 502002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 503e5aaf047SAppaRao Puli return; 504e5aaf047SAppaRao Puli } 5057e860f15SJohn Edward Broadbent const std::string& id = param; 506e5aaf047SAppaRao Puli 5071476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5081476687dSEd Tanous "#EventDestination.v1_7_0.EventDestination"; 5091476687dSEd Tanous asyncResp->res.jsonValue["Protocol"] = "Redfish"; 510e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 511e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 512e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 513e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 514002d39b4SEd Tanous asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 515b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 516e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 517b52664e2SAppaRao Puli subValue->subscriptionType; 518002d39b4SEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array(); 519002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 520e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 521b52664e2SAppaRao Puli subValue->registryPrefixes; 522002d39b4SEd Tanous asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 523e56f254cSSunitha Harish 524002d39b4SEd Tanous asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 525002d39b4SEd Tanous asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 526144b6318SAppaRao Puli 5271476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 528144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 529144b6318SAppaRao Puli { 5301476687dSEd Tanous nlohmann::json::object_t mdr; 5311476687dSEd Tanous mdr["@odata.id"] = mdrUri; 5321476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 533144b6318SAppaRao Puli } 534002d39b4SEd Tanous asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 5357e860f15SJohn Edward Broadbent }); 5369d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 537ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 538ed398213SEd Tanous // ConfigureSelf 5397eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 540ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 541432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5427e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 54345ca1b86SEd Tanous [&app](const crow::Request& req, 5447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5457e860f15SJohn Edward Broadbent const std::string& param) { 5463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54745ca1b86SEd Tanous { 54845ca1b86SEd Tanous return; 54945ca1b86SEd Tanous } 550b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5517e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 552b52664e2SAppaRao Puli if (subValue == nullptr) 553e5aaf047SAppaRao Puli { 554002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 555e5aaf047SAppaRao Puli return; 556e5aaf047SAppaRao Puli } 557e5aaf047SAppaRao Puli 558e5aaf047SAppaRao Puli std::optional<std::string> context; 559e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 560e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 561e5aaf047SAppaRao Puli 562002d39b4SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context, 563002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, 564002d39b4SEd Tanous "HttpHeaders", headers)) 565e5aaf047SAppaRao Puli { 566e5aaf047SAppaRao Puli return; 567e5aaf047SAppaRao Puli } 568e5aaf047SAppaRao Puli 569e5aaf047SAppaRao Puli if (context) 570e5aaf047SAppaRao Puli { 571b52664e2SAppaRao Puli subValue->customText = *context; 572e5aaf047SAppaRao Puli } 573e5aaf047SAppaRao Puli 574e5aaf047SAppaRao Puli if (headers) 575e5aaf047SAppaRao Puli { 576601c71aeSEd Tanous boost::beast::http::fields fields; 577601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 578601c71aeSEd Tanous { 57962bafc01SPatrick Williams for (const auto& it : headerChunk.items()) 580601c71aeSEd Tanous { 581601c71aeSEd Tanous const std::string* value = 582601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 583601c71aeSEd Tanous if (value == nullptr) 584601c71aeSEd Tanous { 585601c71aeSEd Tanous messages::propertyValueFormatError( 586002d39b4SEd Tanous asyncResp->res, it.value().dump(2, ' ', true), 587601c71aeSEd Tanous "HttpHeaders/" + it.key()); 588601c71aeSEd Tanous return; 589601c71aeSEd Tanous } 590601c71aeSEd Tanous fields.set(it.key(), *value); 591601c71aeSEd Tanous } 592601c71aeSEd Tanous } 593601c71aeSEd Tanous subValue->httpHeaders = fields; 594e5aaf047SAppaRao Puli } 595e5aaf047SAppaRao Puli 596e5aaf047SAppaRao Puli if (retryPolicy) 597e5aaf047SAppaRao Puli { 598e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 599e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 600e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 601e5aaf047SAppaRao Puli { 602002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 603e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 604e5aaf047SAppaRao Puli return; 605e5aaf047SAppaRao Puli } 606b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 607fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 608e5aaf047SAppaRao Puli } 609e5aaf047SAppaRao Puli 610b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6117e860f15SJohn Edward Broadbent }); 6129d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 613ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 614ed398213SEd Tanous // ConfigureSelf 6157eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 616ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 617432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6187e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 61945ca1b86SEd Tanous [&app](const crow::Request& req, 6207e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6217e860f15SJohn Edward Broadbent const std::string& param) { 6223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 62345ca1b86SEd Tanous { 62445ca1b86SEd Tanous return; 62545ca1b86SEd Tanous } 626002d39b4SEd Tanous if (!EventServiceManager::getInstance().isSubscriptionExist(param)) 627e5aaf047SAppaRao Puli { 628002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 629e5aaf047SAppaRao Puli return; 630e5aaf047SAppaRao Puli } 6317e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6327e860f15SJohn Edward Broadbent }); 633e5aaf047SAppaRao Puli } 634e5aaf047SAppaRao Puli 635e5aaf047SAppaRao Puli } // namespace redfish 636