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 467e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 47e5aaf047SAppaRao Puli { 487e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 49ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 50002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 51002d39b4SEd Tanous [&app](const crow::Request& req, 52002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5445ca1b86SEd Tanous { 5545ca1b86SEd Tanous return; 5645ca1b86SEd Tanous } 571476687dSEd Tanous 581476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 591476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 601476687dSEd Tanous "#EventService.v1_5_0.EventService"; 611476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 621476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 63*5e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 64*5e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 65*5e44e3d8SAppaRao Puli 661476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 671476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 68002d39b4SEd Tanous asyncResp->res 69002d39b4SEd Tanous .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] = 701476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 71e5aaf047SAppaRao Puli 7228afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 7328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 7428afb49cSJunLin Chen .getEventServiceConfig(); 757d1cc387SAppaRao Puli 767d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7728afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 78002d39b4SEd Tanous asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled; 797e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 8028afb49cSJunLin Chen eventServiceConfig.retryAttempts; 81e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 8228afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 83002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 840fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 850fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8607941a88SAyushi Smriti 87613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 88613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 89613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 90613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 91613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 92613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 93613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 9407941a88SAyushi Smriti 9507941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 96613dabeaSEd Tanous std::move(supportedSSEFilters); 977e860f15SJohn Edward Broadbent }); 98e5aaf047SAppaRao Puli 997e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 100ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1017e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 10245ca1b86SEd Tanous [&app](const crow::Request& req, 10345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1043ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105e5aaf047SAppaRao Puli { 10645ca1b86SEd Tanous return; 10745ca1b86SEd Tanous } 108e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 109e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 110e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 111e5aaf047SAppaRao Puli 11215ed6780SWilly Tu if (!json_util::readJsonPatch( 1137e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1147e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1157e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 116e5aaf047SAppaRao Puli { 117e5aaf047SAppaRao Puli return; 118e5aaf047SAppaRao Puli } 119e5aaf047SAppaRao Puli 12028afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 12128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 12228afb49cSJunLin Chen .getEventServiceConfig(); 1237d1cc387SAppaRao Puli 124e5aaf047SAppaRao Puli if (serviceEnabled) 125e5aaf047SAppaRao Puli { 12628afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 127e5aaf047SAppaRao Puli } 128e5aaf047SAppaRao Puli 129e5aaf047SAppaRao Puli if (retryAttemps) 130e5aaf047SAppaRao Puli { 131e5aaf047SAppaRao Puli // Supported range [1-3] 132e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 133e5aaf047SAppaRao Puli { 134e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 135e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 136e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 137e5aaf047SAppaRao Puli } 138e5aaf047SAppaRao Puli else 139e5aaf047SAppaRao Puli { 14028afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 141e5aaf047SAppaRao Puli } 142e5aaf047SAppaRao Puli } 143e5aaf047SAppaRao Puli 144e5aaf047SAppaRao Puli if (retryInterval) 145e5aaf047SAppaRao Puli { 14633a32b34SGunnar Mills // Supported range [5 - 180] 14733a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 148e5aaf047SAppaRao Puli { 149e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 150e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 15133a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 152e5aaf047SAppaRao Puli } 153e5aaf047SAppaRao Puli else 154e5aaf047SAppaRao Puli { 155002d39b4SEd Tanous eventServiceConfig.retryTimeoutInterval = *retryInterval; 156e5aaf047SAppaRao Puli } 157e5aaf047SAppaRao Puli } 158e5aaf047SAppaRao Puli 1597d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 16028afb49cSJunLin Chen eventServiceConfig); 1617e860f15SJohn Edward Broadbent }); 1620b4bdd93SAppaRao Puli } 1630b4bdd93SAppaRao Puli 1647e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1650b4bdd93SAppaRao Puli { 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; 21389492a15SPatrick Williams member["@odata.id"] = "/redfish/v1/EventService/Subscriptions/" + 21489492a15SPatrick Williams id; 215b2ba3072SPatrick Williams memberArray.emplace_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 256600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 257600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 258600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 259600af5f1SAppaRao Puli { 260600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 261600af5f1SAppaRao Puli maxDestinationSize); 262600af5f1SAppaRao Puli return; 263600af5f1SAppaRao Puli } 264600af5f1SAppaRao Puli 265dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 266dd28ba82SAppaRao Puli { 26726f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 268dd28ba82SAppaRao Puli { 269002d39b4SEd Tanous messages::propertyValueConflict(asyncResp->res, "MessageIds", 270002d39b4SEd Tanous "RegistryPrefixes"); 271dd28ba82SAppaRao Puli return; 272dd28ba82SAppaRao Puli } 273dd28ba82SAppaRao Puli } 274dd28ba82SAppaRao Puli 275eb1c47d3SEd Tanous std::string host; 276eb1c47d3SEd Tanous std::string urlProto; 277eb1c47d3SEd Tanous uint16_t port = 0; 278eb1c47d3SEd Tanous std::string path; 279eb1c47d3SEd Tanous 280002d39b4SEd Tanous if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port, 281002d39b4SEd Tanous path)) 282e5aaf047SAppaRao Puli { 283eb1c47d3SEd Tanous BMCWEB_LOG_WARNING 284eb1c47d3SEd Tanous << "Failed to validate and split destination url"; 285e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 286e5aaf047SAppaRao Puli "Destination"); 287e5aaf047SAppaRao Puli return; 288e5aaf047SAppaRao Puli } 289b52664e2SAppaRao Puli 290b52664e2SAppaRao Puli if (path.empty()) 291b52664e2SAppaRao Puli { 292b52664e2SAppaRao Puli path = "/"; 293b52664e2SAppaRao Puli } 294f8ca6d79SEd Tanous std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>( 295f8ca6d79SEd Tanous host, port, path, urlProto, app.ioContext()); 296b52664e2SAppaRao Puli 297b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 298e5aaf047SAppaRao Puli 299e5aaf047SAppaRao Puli if (subscriptionType) 300e5aaf047SAppaRao Puli { 301e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 302e5aaf047SAppaRao Puli { 303fffb8c1fSEd Tanous messages::propertyValueNotInList( 304fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 305e5aaf047SAppaRao Puli return; 306e5aaf047SAppaRao Puli } 307b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 308e5aaf047SAppaRao Puli } 309e5aaf047SAppaRao Puli else 310e5aaf047SAppaRao Puli { 311b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 312e5aaf047SAppaRao Puli } 313e5aaf047SAppaRao Puli 314e5aaf047SAppaRao Puli if (protocol != "Redfish") 315e5aaf047SAppaRao Puli { 316e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 317e5aaf047SAppaRao Puli "Protocol"); 318e5aaf047SAppaRao Puli return; 319e5aaf047SAppaRao Puli } 320b52664e2SAppaRao Puli subValue->protocol = protocol; 321e5aaf047SAppaRao Puli 32223a21a1cSEd Tanous if (eventFormatType2) 323e5aaf047SAppaRao Puli { 324e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 325e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 326002d39b4SEd Tanous *eventFormatType2) == supportedEvtFormatTypes.end()) 327e5aaf047SAppaRao Puli { 328fffb8c1fSEd Tanous messages::propertyValueNotInList( 329fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 330e5aaf047SAppaRao Puli return; 331e5aaf047SAppaRao Puli } 33223a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 333e5aaf047SAppaRao Puli } 334e5aaf047SAppaRao Puli else 335e5aaf047SAppaRao Puli { 336e5aaf047SAppaRao Puli // If not specified, use default "Event" 33723a21a1cSEd Tanous subValue->eventFormatType = "Event"; 338e5aaf047SAppaRao Puli } 339e5aaf047SAppaRao Puli 340e5aaf047SAppaRao Puli if (context) 341e5aaf047SAppaRao Puli { 342600af5f1SAppaRao Puli // This value is selected aribitrarily. 343600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 344600af5f1SAppaRao Puli if (context->size() > maxContextSize) 345600af5f1SAppaRao Puli { 346600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 347600af5f1SAppaRao Puli maxContextSize); 348600af5f1SAppaRao Puli return; 349600af5f1SAppaRao Puli } 350b52664e2SAppaRao Puli subValue->customText = *context; 351e5aaf047SAppaRao Puli } 352e5aaf047SAppaRao Puli 353e5aaf047SAppaRao Puli if (headers) 354e5aaf047SAppaRao Puli { 355600af5f1SAppaRao Puli size_t cumulativeLen = 0; 356600af5f1SAppaRao Puli 357601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 358601c71aeSEd Tanous { 359600af5f1SAppaRao Puli std::string hdr{headerChunk.dump( 360600af5f1SAppaRao Puli -1, ' ', true, nlohmann::json::error_handler_t::replace)}; 361600af5f1SAppaRao Puli cumulativeLen += hdr.length(); 362600af5f1SAppaRao Puli 363600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 364600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 365600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 366600af5f1SAppaRao Puli { 367600af5f1SAppaRao Puli messages::arraySizeTooLong(asyncResp->res, "HttpHeaders", 368600af5f1SAppaRao Puli maxHeaderSizeED); 369600af5f1SAppaRao Puli return; 370600af5f1SAppaRao Puli } 371601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 372601c71aeSEd Tanous { 373601c71aeSEd Tanous const std::string* value = 374601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 375601c71aeSEd Tanous if (value == nullptr) 376601c71aeSEd Tanous { 377601c71aeSEd Tanous messages::propertyValueFormatError( 378e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 379601c71aeSEd Tanous "HttpHeaders/" + item.key()); 380601c71aeSEd Tanous return; 381601c71aeSEd Tanous } 382601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 383601c71aeSEd Tanous } 384601c71aeSEd Tanous } 385e5aaf047SAppaRao Puli } 386e5aaf047SAppaRao Puli 387e5aaf047SAppaRao Puli if (regPrefixes) 388e5aaf047SAppaRao Puli { 389e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 390e5aaf047SAppaRao Puli { 391e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 392e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 393e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 394e5aaf047SAppaRao Puli { 395fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 396fffb8c1fSEd Tanous "RegistryPrefixes"); 397e5aaf047SAppaRao Puli return; 398e5aaf047SAppaRao Puli } 399e5aaf047SAppaRao Puli } 400b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 401e5aaf047SAppaRao Puli } 402e5aaf047SAppaRao Puli 403e56f254cSSunitha Harish if (resTypes) 404e56f254cSSunitha Harish { 405e56f254cSSunitha Harish for (const std::string& it : *resTypes) 406e56f254cSSunitha Harish { 407e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 408e56f254cSSunitha Harish supportedResourceTypes.end(), 409e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 410e56f254cSSunitha Harish { 411e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 412e56f254cSSunitha Harish "ResourceTypes"); 413e56f254cSSunitha Harish return; 414e56f254cSSunitha Harish } 415e56f254cSSunitha Harish } 416e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 417e56f254cSSunitha Harish } 418e56f254cSSunitha Harish 419e5aaf047SAppaRao Puli if (msgIds) 420e5aaf047SAppaRao Puli { 421b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 422b304bd79SP Dheeraj Srujan Kumar 4237e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4247e860f15SJohn Edward Broadbent // supported prefixes 425b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 426b304bd79SP Dheeraj Srujan Kumar { 427b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 428b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 429b304bd79SP Dheeraj Srujan Kumar } 430b304bd79SP Dheeraj Srujan Kumar else 431b304bd79SP Dheeraj Srujan Kumar { 432b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 433b304bd79SP Dheeraj Srujan Kumar } 434b304bd79SP Dheeraj Srujan Kumar 435b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 436b304bd79SP Dheeraj Srujan Kumar { 437b304bd79SP Dheeraj Srujan Kumar bool validId = false; 438b304bd79SP Dheeraj Srujan Kumar 439b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 440b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 441b304bd79SP Dheeraj Srujan Kumar { 442fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 443fffb8c1fSEd Tanous registry = 444fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 445b304bd79SP Dheeraj Srujan Kumar 446b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 44726702d01SEd Tanous registry.begin(), registry.end(), 448fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 449fffb8c1fSEd Tanous messageEntry) { 45055f79e6fSEd Tanous return id == messageEntry.first; 451b304bd79SP Dheeraj Srujan Kumar })) 452b304bd79SP Dheeraj Srujan Kumar { 453b304bd79SP Dheeraj Srujan Kumar validId = true; 454b304bd79SP Dheeraj Srujan Kumar break; 455b304bd79SP Dheeraj Srujan Kumar } 456b304bd79SP Dheeraj Srujan Kumar } 457b304bd79SP Dheeraj Srujan Kumar 458b304bd79SP Dheeraj Srujan Kumar if (!validId) 459b304bd79SP Dheeraj Srujan Kumar { 460b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 461b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 462b304bd79SP Dheeraj Srujan Kumar return; 463b304bd79SP Dheeraj Srujan Kumar } 464b304bd79SP Dheeraj Srujan Kumar } 465b304bd79SP Dheeraj Srujan Kumar 466b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 467e5aaf047SAppaRao Puli } 468e5aaf047SAppaRao Puli 469e5aaf047SAppaRao Puli if (retryPolicy) 470e5aaf047SAppaRao Puli { 471e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 472e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 473e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 474e5aaf047SAppaRao Puli { 475002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 476002d39b4SEd Tanous "DeliveryRetryPolicy"); 477e5aaf047SAppaRao Puli return; 478e5aaf047SAppaRao Puli } 479b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 480e5aaf047SAppaRao Puli } 481e5aaf047SAppaRao Puli else 482e5aaf047SAppaRao Puli { 483e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 484b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 485e5aaf047SAppaRao Puli } 486e5aaf047SAppaRao Puli 487144b6318SAppaRao Puli if (mrdJsonArray) 488156d6b00SAppaRao Puli { 489144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 490144b6318SAppaRao Puli { 491144b6318SAppaRao Puli std::string mrdUri; 492ea2e6eecSWilly Tu 493002d39b4SEd Tanous if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id", 494002d39b4SEd Tanous mrdUri)) 495ea2e6eecSWilly Tu 496144b6318SAppaRao Puli { 497144b6318SAppaRao Puli return; 498144b6318SAppaRao Puli } 499ea2e6eecSWilly Tu subValue->metricReportDefinitions.emplace_back(mrdUri); 500144b6318SAppaRao Puli } 501156d6b00SAppaRao Puli } 502156d6b00SAppaRao Puli 503b52664e2SAppaRao Puli std::string id = 504fffb8c1fSEd Tanous EventServiceManager::getInstance().addSubscription(subValue); 505b52664e2SAppaRao Puli if (id.empty()) 506e5aaf047SAppaRao Puli { 507e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 508e5aaf047SAppaRao Puli return; 509e5aaf047SAppaRao Puli } 510e5aaf047SAppaRao Puli 511e5aaf047SAppaRao Puli messages::created(asyncResp->res); 512e5aaf047SAppaRao Puli asyncResp->res.addHeader( 513e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 5147e860f15SJohn Edward Broadbent }); 515e5aaf047SAppaRao Puli } 516e5aaf047SAppaRao Puli 5177e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 518e5aaf047SAppaRao Puli { 5199d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 520ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 52245ca1b86SEd Tanous [&app](const crow::Request& req, 5237e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5247e860f15SJohn Edward Broadbent const std::string& param) { 5253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 52645ca1b86SEd Tanous { 52745ca1b86SEd Tanous return; 52845ca1b86SEd Tanous } 529b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5307e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 531b52664e2SAppaRao Puli if (subValue == nullptr) 532e5aaf047SAppaRao Puli { 533002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 534e5aaf047SAppaRao Puli return; 535e5aaf047SAppaRao Puli } 5367e860f15SJohn Edward Broadbent const std::string& id = param; 537e5aaf047SAppaRao Puli 5381476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5391476687dSEd Tanous "#EventDestination.v1_7_0.EventDestination"; 5401476687dSEd Tanous asyncResp->res.jsonValue["Protocol"] = "Redfish"; 541e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 542e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 543e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 544e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 545002d39b4SEd Tanous asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 546b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 547e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 548b52664e2SAppaRao Puli subValue->subscriptionType; 549002d39b4SEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array(); 550002d39b4SEd Tanous asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 551e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 552b52664e2SAppaRao Puli subValue->registryPrefixes; 553002d39b4SEd Tanous asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes; 554e56f254cSSunitha Harish 555002d39b4SEd Tanous asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 556002d39b4SEd Tanous asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 557144b6318SAppaRao Puli 5581476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 559144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 560144b6318SAppaRao Puli { 5611476687dSEd Tanous nlohmann::json::object_t mdr; 5621476687dSEd Tanous mdr["@odata.id"] = mdrUri; 5631476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 564144b6318SAppaRao Puli } 565002d39b4SEd Tanous asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; 5667e860f15SJohn Edward Broadbent }); 5679d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 568ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 569ed398213SEd Tanous // ConfigureSelf 5707eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 571ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 572432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5737e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 57445ca1b86SEd Tanous [&app](const crow::Request& req, 5757e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5767e860f15SJohn Edward Broadbent const std::string& param) { 5773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 57845ca1b86SEd Tanous { 57945ca1b86SEd Tanous return; 58045ca1b86SEd Tanous } 581b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5827e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 583b52664e2SAppaRao Puli if (subValue == nullptr) 584e5aaf047SAppaRao Puli { 585002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 586e5aaf047SAppaRao Puli return; 587e5aaf047SAppaRao Puli } 588e5aaf047SAppaRao Puli 589e5aaf047SAppaRao Puli std::optional<std::string> context; 590e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 591e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 592e5aaf047SAppaRao Puli 593002d39b4SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context, 594002d39b4SEd Tanous "DeliveryRetryPolicy", retryPolicy, 595002d39b4SEd Tanous "HttpHeaders", headers)) 596e5aaf047SAppaRao Puli { 597e5aaf047SAppaRao Puli return; 598e5aaf047SAppaRao Puli } 599e5aaf047SAppaRao Puli 600e5aaf047SAppaRao Puli if (context) 601e5aaf047SAppaRao Puli { 602b52664e2SAppaRao Puli subValue->customText = *context; 603e5aaf047SAppaRao Puli } 604e5aaf047SAppaRao Puli 605e5aaf047SAppaRao Puli if (headers) 606e5aaf047SAppaRao Puli { 607601c71aeSEd Tanous boost::beast::http::fields fields; 608601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 609601c71aeSEd Tanous { 61062bafc01SPatrick Williams for (const auto& it : headerChunk.items()) 611601c71aeSEd Tanous { 612601c71aeSEd Tanous const std::string* value = 613601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 614601c71aeSEd Tanous if (value == nullptr) 615601c71aeSEd Tanous { 616601c71aeSEd Tanous messages::propertyValueFormatError( 617002d39b4SEd Tanous asyncResp->res, it.value().dump(2, ' ', true), 618601c71aeSEd Tanous "HttpHeaders/" + it.key()); 619601c71aeSEd Tanous return; 620601c71aeSEd Tanous } 621601c71aeSEd Tanous fields.set(it.key(), *value); 622601c71aeSEd Tanous } 623601c71aeSEd Tanous } 624601c71aeSEd Tanous subValue->httpHeaders = fields; 625e5aaf047SAppaRao Puli } 626e5aaf047SAppaRao Puli 627e5aaf047SAppaRao Puli if (retryPolicy) 628e5aaf047SAppaRao Puli { 629e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 630e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 631e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 632e5aaf047SAppaRao Puli { 633002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 634e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 635e5aaf047SAppaRao Puli return; 636e5aaf047SAppaRao Puli } 637b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 638e5aaf047SAppaRao Puli } 639e5aaf047SAppaRao Puli 640b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6417e860f15SJohn Edward Broadbent }); 6429d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 643ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 644ed398213SEd Tanous // ConfigureSelf 6457eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 646ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 647432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 64945ca1b86SEd Tanous [&app](const crow::Request& req, 6507e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6517e860f15SJohn Edward Broadbent const std::string& param) { 6523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65345ca1b86SEd Tanous { 65445ca1b86SEd Tanous return; 65545ca1b86SEd Tanous } 656002d39b4SEd Tanous if (!EventServiceManager::getInstance().isSubscriptionExist(param)) 657e5aaf047SAppaRao Puli { 658002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 659e5aaf047SAppaRao Puli return; 660e5aaf047SAppaRao Puli } 6617e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6627e860f15SJohn Edward Broadbent }); 663e5aaf047SAppaRao Puli } 664e5aaf047SAppaRao Puli 665e5aaf047SAppaRao Puli } // namespace redfish 666