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; 214b2ba3072SPatrick 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 255*600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 256*600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 257*600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 258*600af5f1SAppaRao Puli { 259*600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 260*600af5f1SAppaRao Puli maxDestinationSize); 261*600af5f1SAppaRao Puli return; 262*600af5f1SAppaRao Puli } 263*600af5f1SAppaRao Puli 264dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 265dd28ba82SAppaRao Puli { 26626f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 267dd28ba82SAppaRao Puli { 268002d39b4SEd Tanous messages::propertyValueConflict(asyncResp->res, "MessageIds", 269002d39b4SEd Tanous "RegistryPrefixes"); 270dd28ba82SAppaRao Puli return; 271dd28ba82SAppaRao Puli } 272dd28ba82SAppaRao Puli } 273dd28ba82SAppaRao Puli 274eb1c47d3SEd Tanous std::string host; 275eb1c47d3SEd Tanous std::string urlProto; 276eb1c47d3SEd Tanous uint16_t port = 0; 277eb1c47d3SEd Tanous std::string path; 278eb1c47d3SEd Tanous 279002d39b4SEd Tanous if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port, 280002d39b4SEd Tanous path)) 281e5aaf047SAppaRao Puli { 282eb1c47d3SEd Tanous BMCWEB_LOG_WARNING 283eb1c47d3SEd Tanous << "Failed to validate and split destination url"; 284e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 285e5aaf047SAppaRao Puli "Destination"); 286e5aaf047SAppaRao Puli return; 287e5aaf047SAppaRao Puli } 288b52664e2SAppaRao Puli 289b52664e2SAppaRao Puli if (path.empty()) 290b52664e2SAppaRao Puli { 291b52664e2SAppaRao Puli path = "/"; 292b52664e2SAppaRao Puli } 293f8ca6d79SEd Tanous std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>( 294f8ca6d79SEd Tanous host, port, path, urlProto, app.ioContext()); 295b52664e2SAppaRao Puli 296b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 297e5aaf047SAppaRao Puli 298e5aaf047SAppaRao Puli if (subscriptionType) 299e5aaf047SAppaRao Puli { 300e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 301e5aaf047SAppaRao Puli { 302fffb8c1fSEd Tanous messages::propertyValueNotInList( 303fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 304e5aaf047SAppaRao Puli return; 305e5aaf047SAppaRao Puli } 306b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 307e5aaf047SAppaRao Puli } 308e5aaf047SAppaRao Puli else 309e5aaf047SAppaRao Puli { 310b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 311e5aaf047SAppaRao Puli } 312e5aaf047SAppaRao Puli 313e5aaf047SAppaRao Puli if (protocol != "Redfish") 314e5aaf047SAppaRao Puli { 315e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 316e5aaf047SAppaRao Puli "Protocol"); 317e5aaf047SAppaRao Puli return; 318e5aaf047SAppaRao Puli } 319b52664e2SAppaRao Puli subValue->protocol = protocol; 320e5aaf047SAppaRao Puli 32123a21a1cSEd Tanous if (eventFormatType2) 322e5aaf047SAppaRao Puli { 323e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 324e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 325002d39b4SEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 326e5aaf047SAppaRao Puli { 327fffb8c1fSEd Tanous messages::propertyValueNotInList( 328fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 329e5aaf047SAppaRao Puli return; 330e5aaf047SAppaRao Puli } 33123a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 332e5aaf047SAppaRao Puli } 333e5aaf047SAppaRao Puli else 334e5aaf047SAppaRao Puli { 335e5aaf047SAppaRao Puli // If not specified, use default "Event" 33623a21a1cSEd Tanous subValue->eventFormatType = "Event"; 337e5aaf047SAppaRao Puli } 338e5aaf047SAppaRao Puli 339e5aaf047SAppaRao Puli if (context) 340e5aaf047SAppaRao Puli { 341*600af5f1SAppaRao Puli // This value is selected aribitrarily. 342*600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 343*600af5f1SAppaRao Puli if (context->size() > maxContextSize) 344*600af5f1SAppaRao Puli { 345*600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 346*600af5f1SAppaRao Puli maxContextSize); 347*600af5f1SAppaRao Puli return; 348*600af5f1SAppaRao Puli } 349b52664e2SAppaRao Puli subValue->customText = *context; 350e5aaf047SAppaRao Puli } 351e5aaf047SAppaRao Puli 352e5aaf047SAppaRao Puli if (headers) 353e5aaf047SAppaRao Puli { 354*600af5f1SAppaRao Puli size_t cumulativeLen = 0; 355*600af5f1SAppaRao Puli 356601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 357601c71aeSEd Tanous { 358*600af5f1SAppaRao Puli std::string hdr{headerChunk.dump( 359*600af5f1SAppaRao Puli -1, ' ', true, nlohmann::json::error_handler_t::replace)}; 360*600af5f1SAppaRao Puli cumulativeLen += hdr.length(); 361*600af5f1SAppaRao Puli 362*600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 363*600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 364*600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 365*600af5f1SAppaRao Puli { 366*600af5f1SAppaRao Puli messages::arraySizeTooLong(asyncResp->res, "HttpHeaders", 367*600af5f1SAppaRao Puli maxHeaderSizeED); 368*600af5f1SAppaRao Puli return; 369*600af5f1SAppaRao Puli } 370601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 371601c71aeSEd Tanous { 372601c71aeSEd Tanous const std::string* value = 373601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 374601c71aeSEd Tanous if (value == nullptr) 375601c71aeSEd Tanous { 376601c71aeSEd Tanous messages::propertyValueFormatError( 377e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 378601c71aeSEd Tanous "HttpHeaders/" + item.key()); 379601c71aeSEd Tanous return; 380601c71aeSEd Tanous } 381601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 382601c71aeSEd Tanous } 383601c71aeSEd Tanous } 384e5aaf047SAppaRao Puli } 385e5aaf047SAppaRao Puli 386e5aaf047SAppaRao Puli if (regPrefixes) 387e5aaf047SAppaRao Puli { 388e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 389e5aaf047SAppaRao Puli { 390e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 391e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 392e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 393e5aaf047SAppaRao Puli { 394fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 395fffb8c1fSEd Tanous "RegistryPrefixes"); 396e5aaf047SAppaRao Puli return; 397e5aaf047SAppaRao Puli } 398e5aaf047SAppaRao Puli } 399b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 400e5aaf047SAppaRao Puli } 401e5aaf047SAppaRao Puli 402e56f254cSSunitha Harish if (resTypes) 403e56f254cSSunitha Harish { 404e56f254cSSunitha Harish for (const std::string& it : *resTypes) 405e56f254cSSunitha Harish { 406e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 407e56f254cSSunitha Harish supportedResourceTypes.end(), 408e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 409e56f254cSSunitha Harish { 410e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 411e56f254cSSunitha Harish "ResourceTypes"); 412e56f254cSSunitha Harish return; 413e56f254cSSunitha Harish } 414e56f254cSSunitha Harish } 415e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 416e56f254cSSunitha Harish } 417e56f254cSSunitha Harish 418e5aaf047SAppaRao Puli if (msgIds) 419e5aaf047SAppaRao Puli { 420b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 421b304bd79SP Dheeraj Srujan Kumar 4227e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4237e860f15SJohn Edward Broadbent // supported prefixes 424b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 425b304bd79SP Dheeraj Srujan Kumar { 426b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 427b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 428b304bd79SP Dheeraj Srujan Kumar } 429b304bd79SP Dheeraj Srujan Kumar else 430b304bd79SP Dheeraj Srujan Kumar { 431b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 432b304bd79SP Dheeraj Srujan Kumar } 433b304bd79SP Dheeraj Srujan Kumar 434b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 435b304bd79SP Dheeraj Srujan Kumar { 436b304bd79SP Dheeraj Srujan Kumar bool validId = false; 437b304bd79SP Dheeraj Srujan Kumar 438b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 439b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 440b304bd79SP Dheeraj Srujan Kumar { 441fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 442fffb8c1fSEd Tanous registry = 443fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 444b304bd79SP Dheeraj Srujan Kumar 445b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 44626702d01SEd Tanous registry.begin(), registry.end(), 447fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 448fffb8c1fSEd Tanous messageEntry) { 44955f79e6fSEd Tanous return id == messageEntry.first; 450b304bd79SP Dheeraj Srujan Kumar })) 451b304bd79SP Dheeraj Srujan Kumar { 452b304bd79SP Dheeraj Srujan Kumar validId = true; 453b304bd79SP Dheeraj Srujan Kumar break; 454b304bd79SP Dheeraj Srujan Kumar } 455b304bd79SP Dheeraj Srujan Kumar } 456b304bd79SP Dheeraj Srujan Kumar 457b304bd79SP Dheeraj Srujan Kumar if (!validId) 458b304bd79SP Dheeraj Srujan Kumar { 459b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 460b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 461b304bd79SP Dheeraj Srujan Kumar return; 462b304bd79SP Dheeraj Srujan Kumar } 463b304bd79SP Dheeraj Srujan Kumar } 464b304bd79SP Dheeraj Srujan Kumar 465b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 466e5aaf047SAppaRao Puli } 467e5aaf047SAppaRao Puli 468e5aaf047SAppaRao Puli if (retryPolicy) 469e5aaf047SAppaRao Puli { 470e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 471e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 472e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 473e5aaf047SAppaRao Puli { 474002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 475002d39b4SEd Tanous "DeliveryRetryPolicy"); 476e5aaf047SAppaRao Puli return; 477e5aaf047SAppaRao Puli } 478b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 479e5aaf047SAppaRao Puli } 480e5aaf047SAppaRao Puli else 481e5aaf047SAppaRao Puli { 482e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 483b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 484e5aaf047SAppaRao Puli } 485e5aaf047SAppaRao Puli 486144b6318SAppaRao Puli if (mrdJsonArray) 487156d6b00SAppaRao Puli { 488144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 489144b6318SAppaRao Puli { 490144b6318SAppaRao Puli std::string mrdUri; 491ea2e6eecSWilly Tu 492002d39b4SEd Tanous if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id", 493002d39b4SEd Tanous mrdUri)) 494ea2e6eecSWilly Tu 495144b6318SAppaRao Puli { 496144b6318SAppaRao Puli return; 497144b6318SAppaRao Puli } 498ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 499144b6318SAppaRao Puli } 500156d6b00SAppaRao Puli } 501156d6b00SAppaRao Puli 502b52664e2SAppaRao Puli std::string id = 503fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 504b52664e2SAppaRao Puli if (id.empty()) 505e5aaf047SAppaRao Puli { 506e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 507e5aaf047SAppaRao Puli return; 508e5aaf047SAppaRao Puli } 509e5aaf047SAppaRao Puli 510e5aaf047SAppaRao Puli messages::created(asyncResp->res); 511e5aaf047SAppaRao Puli asyncResp->res.addHeader( 512e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 5137e860f15SJohn Edward Broadbent }); 514e5aaf047SAppaRao Puli } 515e5aaf047SAppaRao Puli 5167e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 517e5aaf047SAppaRao Puli { 5189d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 519ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5207e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 52145ca1b86SEd Tanous [&app](const crow::Request& req, 5227e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5237e860f15SJohn Edward Broadbent const std::string& param) { 5243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 52545ca1b86SEd Tanous { 52645ca1b86SEd Tanous return; 52745ca1b86SEd Tanous } 528b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5297e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 530b52664e2SAppaRao Puli if (subValue == nullptr) 531e5aaf047SAppaRao Puli { 532002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 533e5aaf047SAppaRao Puli return; 534e5aaf047SAppaRao Puli } 5357e860f15SJohn Edward Broadbent const std::string& id = param; 536e5aaf047SAppaRao Puli 5371476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5381476687dSEd Tanous "#EventDestination.v1_7_0.EventDestination"; 5391476687dSEd Tanous asyncResp->res.jsonValue["Protocol"] = "Redfish"; 540e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 541e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 542e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 543e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 544002d39b4SEd Tanous asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 545b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 546e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 547b52664e2SAppaRao Puli subValue->subscriptionType; 548002d39b4SEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array(); 549002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 550e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 551b52664e2SAppaRao Puli subValue->registryPrefixes; 552002d39b4SEd Tanous asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 553e56f254cSSunitha Harish 554002d39b4SEd Tanous asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 555002d39b4SEd Tanous asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 556144b6318SAppaRao Puli 5571476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 558144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 559144b6318SAppaRao Puli { 5601476687dSEd Tanous nlohmann::json::object_t mdr; 5611476687dSEd Tanous mdr["@odata.id"] = mdrUri; 5621476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 563144b6318SAppaRao Puli } 564002d39b4SEd Tanous asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 5657e860f15SJohn Edward Broadbent }); 5669d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 567ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 568ed398213SEd Tanous // ConfigureSelf 5697eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 570ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 571432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5727e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 57345ca1b86SEd Tanous [&app](const crow::Request& req, 5747e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5757e860f15SJohn Edward Broadbent const std::string& param) { 5763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 57745ca1b86SEd Tanous { 57845ca1b86SEd Tanous return; 57945ca1b86SEd Tanous } 580b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5817e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 582b52664e2SAppaRao Puli if (subValue == nullptr) 583e5aaf047SAppaRao Puli { 584002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 585e5aaf047SAppaRao Puli return; 586e5aaf047SAppaRao Puli } 587e5aaf047SAppaRao Puli 588e5aaf047SAppaRao Puli std::optional<std::string> context; 589e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 590e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 591e5aaf047SAppaRao Puli 592002d39b4SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context, 593002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, 594002d39b4SEd Tanous "HttpHeaders", headers)) 595e5aaf047SAppaRao Puli { 596e5aaf047SAppaRao Puli return; 597e5aaf047SAppaRao Puli } 598e5aaf047SAppaRao Puli 599e5aaf047SAppaRao Puli if (context) 600e5aaf047SAppaRao Puli { 601b52664e2SAppaRao Puli subValue->customText = *context; 602e5aaf047SAppaRao Puli } 603e5aaf047SAppaRao Puli 604e5aaf047SAppaRao Puli if (headers) 605e5aaf047SAppaRao Puli { 606601c71aeSEd Tanous boost::beast::http::fields fields; 607601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 608601c71aeSEd Tanous { 60962bafc01SPatrick Williams for (const auto& it : headerChunk.items()) 610601c71aeSEd Tanous { 611601c71aeSEd Tanous const std::string* value = 612601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 613601c71aeSEd Tanous if (value == nullptr) 614601c71aeSEd Tanous { 615601c71aeSEd Tanous messages::propertyValueFormatError( 616002d39b4SEd Tanous asyncResp->res, it.value().dump(2, ' ', true), 617601c71aeSEd Tanous "HttpHeaders/" + it.key()); 618601c71aeSEd Tanous return; 619601c71aeSEd Tanous } 620601c71aeSEd Tanous fields.set(it.key(), *value); 621601c71aeSEd Tanous } 622601c71aeSEd Tanous } 623601c71aeSEd Tanous subValue->httpHeaders = fields; 624e5aaf047SAppaRao Puli } 625e5aaf047SAppaRao Puli 626e5aaf047SAppaRao Puli if (retryPolicy) 627e5aaf047SAppaRao Puli { 628e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 629e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 630e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 631e5aaf047SAppaRao Puli { 632002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 633e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 634e5aaf047SAppaRao Puli return; 635e5aaf047SAppaRao Puli } 636b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 637e5aaf047SAppaRao Puli } 638e5aaf047SAppaRao Puli 639b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6407e860f15SJohn Edward Broadbent }); 6419d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 642ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 643ed398213SEd Tanous // ConfigureSelf 6447eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 645ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 646432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6477e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 64845ca1b86SEd Tanous [&app](const crow::Request& req, 6497e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6507e860f15SJohn Edward Broadbent const std::string& param) { 6513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65245ca1b86SEd Tanous { 65345ca1b86SEd Tanous return; 65445ca1b86SEd Tanous } 655002d39b4SEd Tanous if (!EventServiceManager::getInstance().isSubscriptionExist(param)) 656e5aaf047SAppaRao Puli { 657002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 658e5aaf047SAppaRao Puli return; 659e5aaf047SAppaRao Puli } 6607e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6617e860f15SJohn Edward Broadbent }); 662e5aaf047SAppaRao Puli } 663e5aaf047SAppaRao Puli 664e5aaf047SAppaRao Puli } // namespace redfish 665