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> 21ed398213SEd Tanous #include <registries/privilege_registry.hpp> 22ed398213SEd Tanous 231e270c5fSPatrick Williams #include <span> 241e270c5fSPatrick Williams 25e5aaf047SAppaRao Puli namespace redfish 26e5aaf047SAppaRao Puli { 27e5aaf047SAppaRao Puli 28156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 29156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 31b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 32e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 33e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 34e5aaf047SAppaRao Puli 35e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 36e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 37e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 38e56f254cSSunitha Harish #else 39e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 40e56f254cSSunitha Harish "Task"}; 41e56f254cSSunitha Harish #endif 42e56f254cSSunitha Harish 43e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 44e5aaf047SAppaRao Puli 457e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 46e5aaf047SAppaRao Puli { 477e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 48ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 490fda0f12SGeorge Liu .methods( 500fda0f12SGeorge Liu boost::beast::http::verb:: 510fda0f12SGeorge Liu get)([](const crow::Request&, 527e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 538d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 54e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 55e5aaf047SAppaRao Puli {"Id", "EventService"}, 56e5aaf047SAppaRao Puli {"Name", "Event Service"}, 57e5aaf047SAppaRao Puli {"Subscriptions", 58e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 590b4bdd93SAppaRao Puli {"Actions", 600b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 610fda0f12SGeorge Liu {{"target", 620fda0f12SGeorge Liu "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}}, 63e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 64e5aaf047SAppaRao Puli 6528afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 6628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 6728afb49cSJunLin Chen .getEventServiceConfig(); 687d1cc387SAppaRao Puli 697d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 7028afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 7128afb49cSJunLin Chen asyncResp->res.jsonValue["ServiceEnabled"] = 7228afb49cSJunLin Chen eventServiceConfig.enabled; 737e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 7428afb49cSJunLin Chen eventServiceConfig.retryAttempts; 75e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 7628afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 777e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatTypes"] = 787e860f15SJohn Edward Broadbent supportedEvtFormatTypes; 790fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 800fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 8107941a88SAyushi Smriti 8207941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8307941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8407941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8507941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 8607941a88SAyushi Smriti 8707941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 8807941a88SAyushi Smriti supportedSSEFilters; 897e860f15SJohn Edward Broadbent }); 90e5aaf047SAppaRao Puli 917e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 92ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 937e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 947e860f15SJohn Edward Broadbent [](const crow::Request& req, 957e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 967e860f15SJohn Edward Broadbent 97e5aaf047SAppaRao Puli { 98e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 99e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 100e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 101e5aaf047SAppaRao Puli 1027e860f15SJohn Edward Broadbent if (!json_util::readJson( 1037e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1047e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1057e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 106e5aaf047SAppaRao Puli { 107e5aaf047SAppaRao Puli return; 108e5aaf047SAppaRao Puli } 109e5aaf047SAppaRao Puli 11028afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11228afb49cSJunLin Chen .getEventServiceConfig(); 1137d1cc387SAppaRao Puli 114e5aaf047SAppaRao Puli if (serviceEnabled) 115e5aaf047SAppaRao Puli { 11628afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 117e5aaf047SAppaRao Puli } 118e5aaf047SAppaRao Puli 119e5aaf047SAppaRao Puli if (retryAttemps) 120e5aaf047SAppaRao Puli { 121e5aaf047SAppaRao Puli // Supported range [1-3] 122e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 123e5aaf047SAppaRao Puli { 124e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 125e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 126e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 127e5aaf047SAppaRao Puli } 128e5aaf047SAppaRao Puli else 129e5aaf047SAppaRao Puli { 13028afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 131e5aaf047SAppaRao Puli } 132e5aaf047SAppaRao Puli } 133e5aaf047SAppaRao Puli 134e5aaf047SAppaRao Puli if (retryInterval) 135e5aaf047SAppaRao Puli { 136e5aaf047SAppaRao Puli // Supported range [30 - 180] 137e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 138e5aaf047SAppaRao Puli { 139e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 140e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 141e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 142e5aaf047SAppaRao Puli } 143e5aaf047SAppaRao Puli else 144e5aaf047SAppaRao Puli { 14528afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval = 14628afb49cSJunLin Chen *retryInterval; 147e5aaf047SAppaRao Puli } 148e5aaf047SAppaRao Puli } 149e5aaf047SAppaRao Puli 1507d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15128afb49cSJunLin Chen eventServiceConfig); 1527e860f15SJohn Edward Broadbent }); 1530b4bdd93SAppaRao Puli } 1540b4bdd93SAppaRao Puli 1557e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1560b4bdd93SAppaRao Puli { 1577e860f15SJohn Edward Broadbent 1587e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1597e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 160ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1617e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 1627e860f15SJohn Edward Broadbent [](const crow::Request&, 1637e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1646ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1656ba8c82eSsunharis_in { 1666ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1676ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1686ba8c82eSsunharis_in return; 1696ba8c82eSsunharis_in } 1708d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1717e860f15SJohn Edward Broadbent }); 172e5aaf047SAppaRao Puli } 173e5aaf047SAppaRao Puli 1747e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 175e5aaf047SAppaRao Puli { 1761ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 177ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1787e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 1797e860f15SJohn Edward Broadbent [](const crow::Request&, 1807e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1818d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 182e5aaf047SAppaRao Puli {"@odata.type", 183e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 184e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 185e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 186e5aaf047SAppaRao Puli 1877e860f15SJohn Edward Broadbent nlohmann::json& memberArray = 1887e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 189e5aaf047SAppaRao Puli 190b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 191b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 192b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 1937e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 1947e860f15SJohn Edward Broadbent subscripIds.size(); 195b52664e2SAppaRao Puli 196b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 197e5aaf047SAppaRao Puli { 198e5aaf047SAppaRao Puli memberArray.push_back( 199e5aaf047SAppaRao Puli {{"@odata.id", 200b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 201e5aaf047SAppaRao Puli } 2027e860f15SJohn Edward Broadbent }); 2037e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2047eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 2057e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2067e860f15SJohn Edward Broadbent [](const crow::Request& req, 2077e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2087e860f15SJohn Edward Broadbent if (EventServiceManager::getInstance() 2097e860f15SJohn Edward Broadbent .getNumberOfSubscriptions() >= maxNoOfSubscriptions) 210e5aaf047SAppaRao Puli { 211e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 212e5aaf047SAppaRao Puli return; 213e5aaf047SAppaRao Puli } 214e5aaf047SAppaRao Puli std::string destUrl; 215e5aaf047SAppaRao Puli std::string protocol; 216e5aaf047SAppaRao Puli std::optional<std::string> context; 217e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 21823a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 219e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 220e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 221e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 222e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 223e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 224144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 225e5aaf047SAppaRao Puli 226e5aaf047SAppaRao Puli if (!json_util::readJson( 2277e860f15SJohn Edward Broadbent req, asyncResp->res, "Destination", destUrl, "Context", 2287e860f15SJohn Edward Broadbent context, "Protocol", protocol, "SubscriptionType", 2297e860f15SJohn Edward Broadbent subscriptionType, "EventFormatType", eventFormatType2, 2307e860f15SJohn Edward Broadbent "HttpHeaders", headers, "RegistryPrefixes", regPrefixes, 2317e860f15SJohn Edward Broadbent "MessageIds", msgIds, "DeliveryRetryPolicy", 2327e860f15SJohn Edward Broadbent retryPolicy, "MetricReportDefinitions", mrdJsonArray, 2337e860f15SJohn Edward Broadbent "ResourceTypes", resTypes)) 234e5aaf047SAppaRao Puli { 235e5aaf047SAppaRao Puli return; 236e5aaf047SAppaRao Puli } 237e5aaf047SAppaRao Puli 238dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 239dd28ba82SAppaRao Puli { 24026f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 241dd28ba82SAppaRao Puli { 2420a4304cfSEd Tanous messages::propertyValueConflict( 2430a4304cfSEd Tanous asyncResp->res, "MessageIds", "RegistryPrefixes"); 244dd28ba82SAppaRao Puli return; 245dd28ba82SAppaRao Puli } 246dd28ba82SAppaRao Puli } 247dd28ba82SAppaRao Puli 248e5aaf047SAppaRao Puli // Validate the URL using regex expression 249b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 250b52664e2SAppaRao Puli // protocol: http/https 251b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2524e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 253b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 254b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 255b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 256b52664e2SAppaRao Puli const std::regex urlRegex( 257b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 258b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 259b52664e2SAppaRao Puli std::cmatch match; 260b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 261e5aaf047SAppaRao Puli { 262e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 263e5aaf047SAppaRao Puli "Destination"); 264e5aaf047SAppaRao Puli return; 265e5aaf047SAppaRao Puli } 266b52664e2SAppaRao Puli 2677e860f15SJohn Edward Broadbent std::string uriProto = 2687e860f15SJohn Edward Broadbent std::string(match[1].first, match[1].second); 269b52664e2SAppaRao Puli if (uriProto == "http") 270b52664e2SAppaRao Puli { 271b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 272b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 273b52664e2SAppaRao Puli "Destination"); 274b52664e2SAppaRao Puli return; 275b52664e2SAppaRao Puli #endif 276b52664e2SAppaRao Puli } 277b52664e2SAppaRao Puli 278b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 279b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 280b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 281b52664e2SAppaRao Puli if (port.empty()) 282b52664e2SAppaRao Puli { 283b52664e2SAppaRao Puli if (uriProto == "http") 284b52664e2SAppaRao Puli { 285b52664e2SAppaRao Puli port = "80"; 286b52664e2SAppaRao Puli } 287b52664e2SAppaRao Puli else 288b52664e2SAppaRao Puli { 289b52664e2SAppaRao Puli port = "443"; 290b52664e2SAppaRao Puli } 291b52664e2SAppaRao Puli } 292b52664e2SAppaRao Puli if (path.empty()) 293b52664e2SAppaRao Puli { 294b52664e2SAppaRao Puli path = "/"; 295b52664e2SAppaRao Puli } 296b52664e2SAppaRao Puli 297b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 298b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 299b52664e2SAppaRao Puli 300b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 301e5aaf047SAppaRao Puli 302e5aaf047SAppaRao Puli if (subscriptionType) 303e5aaf047SAppaRao Puli { 304e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 305e5aaf047SAppaRao Puli { 3067e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 3077e860f15SJohn Edward Broadbent *subscriptionType, 3087e860f15SJohn Edward Broadbent "SubscriptionType"); 309e5aaf047SAppaRao Puli return; 310e5aaf047SAppaRao Puli } 311b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 312e5aaf047SAppaRao Puli } 313e5aaf047SAppaRao Puli else 314e5aaf047SAppaRao Puli { 315b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 316e5aaf047SAppaRao Puli } 317e5aaf047SAppaRao Puli 318e5aaf047SAppaRao Puli if (protocol != "Redfish") 319e5aaf047SAppaRao Puli { 320e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 321e5aaf047SAppaRao Puli "Protocol"); 322e5aaf047SAppaRao Puli return; 323e5aaf047SAppaRao Puli } 324b52664e2SAppaRao Puli subValue->protocol = protocol; 325e5aaf047SAppaRao Puli 32623a21a1cSEd Tanous if (eventFormatType2) 327e5aaf047SAppaRao Puli { 328e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 329e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 3307e860f15SJohn Edward Broadbent *eventFormatType2) == 3317e860f15SJohn Edward Broadbent supportedEvtFormatTypes.end()) 332e5aaf047SAppaRao Puli { 3337e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 3347e860f15SJohn Edward Broadbent *eventFormatType2, 3357e860f15SJohn Edward Broadbent "EventFormatType"); 336e5aaf047SAppaRao Puli return; 337e5aaf047SAppaRao Puli } 33823a21a1cSEd Tanous subValue->eventFormatType = *eventFormatType2; 339e5aaf047SAppaRao Puli } 340e5aaf047SAppaRao Puli else 341e5aaf047SAppaRao Puli { 342e5aaf047SAppaRao Puli // If not specified, use default "Event" 34323a21a1cSEd Tanous subValue->eventFormatType = "Event"; 344e5aaf047SAppaRao Puli } 345e5aaf047SAppaRao Puli 346e5aaf047SAppaRao Puli if (context) 347e5aaf047SAppaRao Puli { 348b52664e2SAppaRao Puli subValue->customText = *context; 349e5aaf047SAppaRao Puli } 350e5aaf047SAppaRao Puli 351e5aaf047SAppaRao Puli if (headers) 352e5aaf047SAppaRao Puli { 353601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 354601c71aeSEd Tanous { 355601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 356601c71aeSEd Tanous { 357601c71aeSEd Tanous const std::string* value = 358601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 359601c71aeSEd Tanous if (value == nullptr) 360601c71aeSEd Tanous { 361601c71aeSEd Tanous messages::propertyValueFormatError( 362*e662eae8SEd Tanous asyncResp->res, item.value().dump(2, 1), 363601c71aeSEd Tanous "HttpHeaders/" + item.key()); 364601c71aeSEd Tanous return; 365601c71aeSEd Tanous } 366601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 367601c71aeSEd Tanous } 368601c71aeSEd Tanous } 369e5aaf047SAppaRao Puli } 370e5aaf047SAppaRao Puli 371e5aaf047SAppaRao Puli if (regPrefixes) 372e5aaf047SAppaRao Puli { 373e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 374e5aaf047SAppaRao Puli { 375e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 376e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 377e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 378e5aaf047SAppaRao Puli { 3797e860f15SJohn Edward Broadbent messages::propertyValueNotInList( 3807e860f15SJohn Edward Broadbent asyncResp->res, it, "RegistryPrefixes"); 381e5aaf047SAppaRao Puli return; 382e5aaf047SAppaRao Puli } 383e5aaf047SAppaRao Puli } 384b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 385e5aaf047SAppaRao Puli } 386e5aaf047SAppaRao Puli 387e56f254cSSunitha Harish if (resTypes) 388e56f254cSSunitha Harish { 389e56f254cSSunitha Harish for (const std::string& it : *resTypes) 390e56f254cSSunitha Harish { 391e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 392e56f254cSSunitha Harish supportedResourceTypes.end(), 393e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 394e56f254cSSunitha Harish { 395e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 396e56f254cSSunitha Harish "ResourceTypes"); 397e56f254cSSunitha Harish return; 398e56f254cSSunitha Harish } 399e56f254cSSunitha Harish } 400e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 401e56f254cSSunitha Harish } 402e56f254cSSunitha Harish 403e5aaf047SAppaRao Puli if (msgIds) 404e5aaf047SAppaRao Puli { 405b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 406b304bd79SP Dheeraj Srujan Kumar 4077e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4087e860f15SJohn Edward Broadbent // supported prefixes 409b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 410b304bd79SP Dheeraj Srujan Kumar { 411b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 412b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 413b304bd79SP Dheeraj Srujan Kumar } 414b304bd79SP Dheeraj Srujan Kumar else 415b304bd79SP Dheeraj Srujan Kumar { 416b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 417b304bd79SP Dheeraj Srujan Kumar } 418b304bd79SP Dheeraj Srujan Kumar 419b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 420b304bd79SP Dheeraj Srujan Kumar { 421b304bd79SP Dheeraj Srujan Kumar bool validId = false; 422b304bd79SP Dheeraj Srujan Kumar 423b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 424b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 425b304bd79SP Dheeraj Srujan Kumar { 42626702d01SEd Tanous const std::span< 427b304bd79SP Dheeraj Srujan Kumar const redfish::message_registries::MessageEntry> 4287e860f15SJohn Edward Broadbent registry = redfish::message_registries:: 4297e860f15SJohn Edward Broadbent getRegistryFromPrefix(it); 430b304bd79SP Dheeraj Srujan Kumar 431b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 43226702d01SEd Tanous registry.begin(), registry.end(), 4337e860f15SJohn Edward Broadbent [&id](const redfish::message_registries:: 4347e860f15SJohn Edward Broadbent MessageEntry& messageEntry) { 435*e662eae8SEd Tanous return id.compare(messageEntry.first) == 436*e662eae8SEd Tanous 0; 437b304bd79SP Dheeraj Srujan Kumar })) 438b304bd79SP Dheeraj Srujan Kumar { 439b304bd79SP Dheeraj Srujan Kumar validId = true; 440b304bd79SP Dheeraj Srujan Kumar break; 441b304bd79SP Dheeraj Srujan Kumar } 442b304bd79SP Dheeraj Srujan Kumar } 443b304bd79SP Dheeraj Srujan Kumar 444b304bd79SP Dheeraj Srujan Kumar if (!validId) 445b304bd79SP Dheeraj Srujan Kumar { 446b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 447b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 448b304bd79SP Dheeraj Srujan Kumar return; 449b304bd79SP Dheeraj Srujan Kumar } 450b304bd79SP Dheeraj Srujan Kumar } 451b304bd79SP Dheeraj Srujan Kumar 452b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 453e5aaf047SAppaRao Puli } 454e5aaf047SAppaRao Puli 455e5aaf047SAppaRao Puli if (retryPolicy) 456e5aaf047SAppaRao Puli { 457e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 458e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 459e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 460e5aaf047SAppaRao Puli { 4617e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 4627e860f15SJohn Edward Broadbent *retryPolicy, 463e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 464e5aaf047SAppaRao Puli return; 465e5aaf047SAppaRao Puli } 466b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 467e5aaf047SAppaRao Puli } 468e5aaf047SAppaRao Puli else 469e5aaf047SAppaRao Puli { 470e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 471b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 472e5aaf047SAppaRao Puli } 473e5aaf047SAppaRao Puli 474144b6318SAppaRao Puli if (mrdJsonArray) 475156d6b00SAppaRao Puli { 476144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 477144b6318SAppaRao Puli { 478144b6318SAppaRao Puli std::string mrdUri; 4797e860f15SJohn Edward Broadbent if (json_util::getValueFromJsonObject( 4807e860f15SJohn Edward Broadbent mrdObj, "@odata.id", mrdUri)) 481144b6318SAppaRao Puli { 4827e860f15SJohn Edward Broadbent subValue->metricReportDefinitions.emplace_back( 4837e860f15SJohn Edward Broadbent mrdUri); 484144b6318SAppaRao Puli } 485144b6318SAppaRao Puli else 486144b6318SAppaRao Puli { 487144b6318SAppaRao Puli messages::propertyValueFormatError( 48871f52d96SEd Tanous asyncResp->res, 4897e860f15SJohn Edward Broadbent mrdObj.dump( 4907e860f15SJohn Edward Broadbent 2, ' ', true, 49171f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 492144b6318SAppaRao Puli "MetricReportDefinitions"); 493144b6318SAppaRao Puli return; 494144b6318SAppaRao Puli } 495144b6318SAppaRao Puli } 496156d6b00SAppaRao Puli } 497156d6b00SAppaRao Puli 498b52664e2SAppaRao Puli std::string id = 4997e860f15SJohn Edward Broadbent EventServiceManager::getInstance().addSubscription( 5007e860f15SJohn Edward Broadbent subValue); 501b52664e2SAppaRao Puli if (id.empty()) 502e5aaf047SAppaRao Puli { 503e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 504e5aaf047SAppaRao Puli return; 505e5aaf047SAppaRao Puli } 506e5aaf047SAppaRao Puli 507e5aaf047SAppaRao Puli messages::created(asyncResp->res); 508e5aaf047SAppaRao Puli asyncResp->res.addHeader( 509e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 5107e860f15SJohn Edward Broadbent }); 511e5aaf047SAppaRao Puli } 512e5aaf047SAppaRao Puli 5137e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 514e5aaf047SAppaRao Puli { 5159d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 516ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5177e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 5187e860f15SJohn Edward Broadbent [](const crow::Request&, 5197e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5207e860f15SJohn Edward Broadbent const std::string& param) { 521b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5227e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 523b52664e2SAppaRao Puli if (subValue == nullptr) 524e5aaf047SAppaRao Puli { 5257e860f15SJohn Edward Broadbent asyncResp->res.result( 5267e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 527e5aaf047SAppaRao Puli return; 528e5aaf047SAppaRao Puli } 5297e860f15SJohn Edward Broadbent const std::string& id = param; 530e5aaf047SAppaRao Puli 5318d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 5327e860f15SJohn Edward Broadbent {"@odata.type", 5337e860f15SJohn Edward Broadbent "#EventDestination.v1_7_0.EventDestination"}, 534e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 535e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 536e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 537e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 538e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 5397e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Destination"] = 5407e860f15SJohn Edward Broadbent subValue->destinationUrl; 541b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 542e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 543b52664e2SAppaRao Puli subValue->subscriptionType; 544ad22fefeSEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = 545ad22fefeSEd Tanous nlohmann::json::array(); 5467e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatType"] = 5477e860f15SJohn Edward Broadbent subValue->eventFormatType; 548e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 549b52664e2SAppaRao Puli subValue->registryPrefixes; 5507e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ResourceTypes"] = 5517e860f15SJohn Edward Broadbent subValue->resourceTypes; 552e56f254cSSunitha Harish 5537e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MessageIds"] = 5547e860f15SJohn Edward Broadbent subValue->registryMsgIds; 5557e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryPolicy"] = 5567e860f15SJohn Edward Broadbent subValue->retryPolicy; 557144b6318SAppaRao Puli 558144b6318SAppaRao Puli std::vector<nlohmann::json> mrdJsonArray; 559144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 560144b6318SAppaRao Puli { 561144b6318SAppaRao Puli mrdJsonArray.push_back({{"@odata.id", mdrUri}}); 562144b6318SAppaRao Puli } 5637e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MetricReportDefinitions"] = 5647e860f15SJohn Edward Broadbent 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)( 5737e860f15SJohn Edward Broadbent [](const crow::Request& req, 5747e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5757e860f15SJohn Edward Broadbent const std::string& param) { 576b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5777e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 578b52664e2SAppaRao Puli if (subValue == nullptr) 579e5aaf047SAppaRao Puli { 5807e860f15SJohn Edward Broadbent asyncResp->res.result( 5817e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 582e5aaf047SAppaRao Puli return; 583e5aaf047SAppaRao Puli } 584e5aaf047SAppaRao Puli 585e5aaf047SAppaRao Puli std::optional<std::string> context; 586e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 587e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 588e5aaf047SAppaRao Puli 5897e860f15SJohn Edward Broadbent if (!json_util::readJson(req, asyncResp->res, "Context", 5907e860f15SJohn Edward Broadbent context, "DeliveryRetryPolicy", 5917e860f15SJohn Edward Broadbent retryPolicy, "HttpHeaders", headers)) 592e5aaf047SAppaRao Puli { 593e5aaf047SAppaRao Puli return; 594e5aaf047SAppaRao Puli } 595e5aaf047SAppaRao Puli 596e5aaf047SAppaRao Puli if (context) 597e5aaf047SAppaRao Puli { 598b52664e2SAppaRao Puli subValue->customText = *context; 599e5aaf047SAppaRao Puli } 600e5aaf047SAppaRao Puli 601e5aaf047SAppaRao Puli if (headers) 602e5aaf047SAppaRao Puli { 603601c71aeSEd Tanous boost::beast::http::fields fields; 604601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 605601c71aeSEd Tanous { 606601c71aeSEd Tanous for (auto& it : headerChunk.items()) 607601c71aeSEd Tanous { 608601c71aeSEd Tanous const std::string* value = 609601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 610601c71aeSEd Tanous if (value == nullptr) 611601c71aeSEd Tanous { 612601c71aeSEd Tanous messages::propertyValueFormatError( 613601c71aeSEd Tanous asyncResp->res, 614601c71aeSEd Tanous it.value().dump(2, ' ', true), 615601c71aeSEd Tanous "HttpHeaders/" + it.key()); 616601c71aeSEd Tanous return; 617601c71aeSEd Tanous } 618601c71aeSEd Tanous fields.set(it.key(), *value); 619601c71aeSEd Tanous } 620601c71aeSEd Tanous } 621601c71aeSEd Tanous subValue->httpHeaders = fields; 622e5aaf047SAppaRao Puli } 623e5aaf047SAppaRao Puli 624e5aaf047SAppaRao Puli if (retryPolicy) 625e5aaf047SAppaRao Puli { 626e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 627e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 628e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 629e5aaf047SAppaRao Puli { 6307e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 6317e860f15SJohn Edward Broadbent *retryPolicy, 632e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 633e5aaf047SAppaRao Puli return; 634e5aaf047SAppaRao Puli } 635b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 636fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 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_)( 6487e860f15SJohn Edward Broadbent [](const crow::Request&, 6497e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6507e860f15SJohn Edward Broadbent const std::string& param) { 6517e860f15SJohn Edward Broadbent if (!EventServiceManager::getInstance().isSubscriptionExist( 6527e860f15SJohn Edward Broadbent param)) 653e5aaf047SAppaRao Puli { 6547e860f15SJohn Edward Broadbent asyncResp->res.result( 6557e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 656e5aaf047SAppaRao Puli return; 657e5aaf047SAppaRao Puli } 6587e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6597e860f15SJohn Edward Broadbent }); 660e5aaf047SAppaRao Puli } 661e5aaf047SAppaRao Puli 662e5aaf047SAppaRao Puli } // namespace redfish 663