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> 20*601c71aeSEd Tanous #include <boost/beast/http/fields.hpp> 21ed398213SEd Tanous #include <registries/privilege_registry.hpp> 22ed398213SEd Tanous 23e5aaf047SAppaRao Puli namespace redfish 24e5aaf047SAppaRao Puli { 25e5aaf047SAppaRao Puli 26156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 27156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 28e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 29b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 31e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 32e5aaf047SAppaRao Puli 33e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE 34e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = { 35e56f254cSSunitha Harish "IBMConfigFile", "Task"}; 36e56f254cSSunitha Harish #else 37e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 38e56f254cSSunitha Harish "Task"}; 39e56f254cSSunitha Harish #endif 40e56f254cSSunitha Harish 41e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 42e5aaf047SAppaRao Puli 437e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 44e5aaf047SAppaRao Puli { 457e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 46ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 477e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 487e860f15SJohn Edward Broadbent [](const crow::Request&, 497e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 508d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 51e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 52e5aaf047SAppaRao Puli {"Id", "EventService"}, 53e5aaf047SAppaRao Puli {"Name", "Event Service"}, 54e5aaf047SAppaRao Puli {"Subscriptions", 55e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 560b4bdd93SAppaRao Puli {"Actions", 570b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 580b4bdd93SAppaRao Puli {{"target", "/redfish/v1/EventService/Actions/" 590b4bdd93SAppaRao Puli "EventService.SubmitTestEvent"}}}}}, 60e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 61e5aaf047SAppaRao Puli 6228afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 6328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 6428afb49cSJunLin Chen .getEventServiceConfig(); 657d1cc387SAppaRao Puli 667d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 6728afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 6828afb49cSJunLin Chen asyncResp->res.jsonValue["ServiceEnabled"] = 6928afb49cSJunLin Chen eventServiceConfig.enabled; 707e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 7128afb49cSJunLin Chen eventServiceConfig.retryAttempts; 72e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 7328afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 747e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatTypes"] = 757e860f15SJohn Edward Broadbent supportedEvtFormatTypes; 767e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["RegistryPrefixes"] = 777e860f15SJohn Edward Broadbent supportedRegPrefixes; 787e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ResourceTypes"] = 797e860f15SJohn Edward Broadbent supportedResourceTypes; 8007941a88SAyushi Smriti 8107941a88SAyushi Smriti nlohmann::json supportedSSEFilters = { 8207941a88SAyushi Smriti {"EventFormatType", true}, {"MessageId", true}, 8307941a88SAyushi Smriti {"MetricReportDefinition", true}, {"RegistryPrefix", true}, 8407941a88SAyushi Smriti {"OriginResource", false}, {"ResourceType", false}}; 8507941a88SAyushi Smriti 8607941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 8707941a88SAyushi Smriti supportedSSEFilters; 887e860f15SJohn Edward Broadbent }); 89e5aaf047SAppaRao Puli 907e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 91ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 927e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 937e860f15SJohn Edward Broadbent [](const crow::Request& req, 947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 957e860f15SJohn Edward Broadbent 96e5aaf047SAppaRao Puli { 97e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 98e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 99e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 100e5aaf047SAppaRao Puli 1017e860f15SJohn Edward Broadbent if (!json_util::readJson( 1027e860f15SJohn Edward Broadbent req, asyncResp->res, "ServiceEnabled", serviceEnabled, 1037e860f15SJohn Edward Broadbent "DeliveryRetryAttempts", retryAttemps, 1047e860f15SJohn Edward Broadbent "DeliveryRetryIntervalSeconds", retryInterval)) 105e5aaf047SAppaRao Puli { 106e5aaf047SAppaRao Puli return; 107e5aaf047SAppaRao Puli } 108e5aaf047SAppaRao Puli 10928afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11128afb49cSJunLin Chen .getEventServiceConfig(); 1127d1cc387SAppaRao Puli 113e5aaf047SAppaRao Puli if (serviceEnabled) 114e5aaf047SAppaRao Puli { 11528afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 116e5aaf047SAppaRao Puli } 117e5aaf047SAppaRao Puli 118e5aaf047SAppaRao Puli if (retryAttemps) 119e5aaf047SAppaRao Puli { 120e5aaf047SAppaRao Puli // Supported range [1-3] 121e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 122e5aaf047SAppaRao Puli { 123e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 124e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 125e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 126e5aaf047SAppaRao Puli } 127e5aaf047SAppaRao Puli else 128e5aaf047SAppaRao Puli { 12928afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 130e5aaf047SAppaRao Puli } 131e5aaf047SAppaRao Puli } 132e5aaf047SAppaRao Puli 133e5aaf047SAppaRao Puli if (retryInterval) 134e5aaf047SAppaRao Puli { 135e5aaf047SAppaRao Puli // Supported range [30 - 180] 136e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 137e5aaf047SAppaRao Puli { 138e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 139e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 140e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 141e5aaf047SAppaRao Puli } 142e5aaf047SAppaRao Puli else 143e5aaf047SAppaRao Puli { 14428afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval = 14528afb49cSJunLin Chen *retryInterval; 146e5aaf047SAppaRao Puli } 147e5aaf047SAppaRao Puli } 148e5aaf047SAppaRao Puli 1497d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 15028afb49cSJunLin Chen eventServiceConfig); 1517e860f15SJohn Edward Broadbent }); 1520b4bdd93SAppaRao Puli } 1530b4bdd93SAppaRao Puli 1547e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1550b4bdd93SAppaRao Puli { 1567e860f15SJohn Edward Broadbent 1577e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1587e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 159ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 1617e860f15SJohn Edward Broadbent [](const crow::Request&, 1627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1630b4bdd93SAppaRao Puli EventServiceManager::getInstance().sendTestEventLog(); 1648d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1657e860f15SJohn Edward Broadbent }); 166e5aaf047SAppaRao Puli } 167e5aaf047SAppaRao Puli 1687e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 169e5aaf047SAppaRao Puli { 1707e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions") 171ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 1727e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 1737e860f15SJohn Edward Broadbent [](const crow::Request&, 1747e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1758d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 176e5aaf047SAppaRao Puli {"@odata.type", 177e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 178e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 179e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 180e5aaf047SAppaRao Puli 1817e860f15SJohn Edward Broadbent nlohmann::json& memberArray = 1827e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 183e5aaf047SAppaRao Puli 184b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 185b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 186b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 1877e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 1887e860f15SJohn Edward Broadbent subscripIds.size(); 189b52664e2SAppaRao Puli 190b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 191e5aaf047SAppaRao Puli { 192e5aaf047SAppaRao Puli memberArray.push_back( 193e5aaf047SAppaRao Puli {{"@odata.id", 194b52664e2SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id}}); 195e5aaf047SAppaRao Puli } 1967e860f15SJohn Edward Broadbent }); 1977e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 1987eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 1997e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2007e860f15SJohn Edward Broadbent [](const crow::Request& req, 2017e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2027e860f15SJohn Edward Broadbent if (EventServiceManager::getInstance() 2037e860f15SJohn Edward Broadbent .getNumberOfSubscriptions() >= maxNoOfSubscriptions) 204e5aaf047SAppaRao Puli { 205e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 206e5aaf047SAppaRao Puli return; 207e5aaf047SAppaRao Puli } 208e5aaf047SAppaRao Puli std::string destUrl; 209e5aaf047SAppaRao Puli std::string protocol; 210e5aaf047SAppaRao Puli std::optional<std::string> context; 211e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 21223a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 213e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 214e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 215e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 216e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 217e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 218144b6318SAppaRao Puli std::optional<std::vector<nlohmann::json>> mrdJsonArray; 219e5aaf047SAppaRao Puli 220e5aaf047SAppaRao Puli if (!json_util::readJson( 2217e860f15SJohn Edward Broadbent req, asyncResp->res, "Destination", destUrl, "Context", 2227e860f15SJohn Edward Broadbent context, "Protocol", protocol, "SubscriptionType", 2237e860f15SJohn Edward Broadbent subscriptionType, "EventFormatType", eventFormatType2, 2247e860f15SJohn Edward Broadbent "HttpHeaders", headers, "RegistryPrefixes", regPrefixes, 2257e860f15SJohn Edward Broadbent "MessageIds", msgIds, "DeliveryRetryPolicy", 2267e860f15SJohn Edward Broadbent retryPolicy, "MetricReportDefinitions", mrdJsonArray, 2277e860f15SJohn Edward Broadbent "ResourceTypes", resTypes)) 228e5aaf047SAppaRao Puli { 229e5aaf047SAppaRao Puli return; 230e5aaf047SAppaRao Puli } 231e5aaf047SAppaRao Puli 232dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 233dd28ba82SAppaRao Puli { 234dd28ba82SAppaRao Puli if (regPrefixes->size() && msgIds->size()) 235dd28ba82SAppaRao Puli { 236dd28ba82SAppaRao Puli messages::mutualExclusiveProperties( 237dd28ba82SAppaRao Puli asyncResp->res, "RegistryPrefixes", "MessageIds"); 238dd28ba82SAppaRao Puli return; 239dd28ba82SAppaRao Puli } 240dd28ba82SAppaRao Puli } 241dd28ba82SAppaRao Puli 242e5aaf047SAppaRao Puli // Validate the URL using regex expression 243b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 244b52664e2SAppaRao Puli // protocol: http/https 245b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 2464e0453b1SGunnar Mills // port: Empty or numeric value with ':' separator. 247b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 248b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 249b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 250b52664e2SAppaRao Puli const std::regex urlRegex( 251b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 252b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 253b52664e2SAppaRao Puli std::cmatch match; 254b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 255e5aaf047SAppaRao Puli { 256e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 257e5aaf047SAppaRao Puli "Destination"); 258e5aaf047SAppaRao Puli return; 259e5aaf047SAppaRao Puli } 260b52664e2SAppaRao Puli 2617e860f15SJohn Edward Broadbent std::string uriProto = 2627e860f15SJohn Edward Broadbent std::string(match[1].first, match[1].second); 263b52664e2SAppaRao Puli if (uriProto == "http") 264b52664e2SAppaRao Puli { 265b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 266b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 267b52664e2SAppaRao Puli "Destination"); 268b52664e2SAppaRao Puli return; 269b52664e2SAppaRao Puli #endif 270b52664e2SAppaRao Puli } 271b52664e2SAppaRao Puli 272b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 273b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 274b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 275b52664e2SAppaRao Puli if (port.empty()) 276b52664e2SAppaRao Puli { 277b52664e2SAppaRao Puli if (uriProto == "http") 278b52664e2SAppaRao Puli { 279b52664e2SAppaRao Puli port = "80"; 280b52664e2SAppaRao Puli } 281b52664e2SAppaRao Puli else 282b52664e2SAppaRao Puli { 283b52664e2SAppaRao Puli port = "443"; 284b52664e2SAppaRao Puli } 285b52664e2SAppaRao Puli } 286b52664e2SAppaRao Puli if (path.empty()) 287b52664e2SAppaRao Puli { 288b52664e2SAppaRao Puli path = "/"; 289b52664e2SAppaRao Puli } 290b52664e2SAppaRao Puli 291b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 292b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 293b52664e2SAppaRao Puli 294b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 295e5aaf047SAppaRao Puli 296e5aaf047SAppaRao Puli if (subscriptionType) 297e5aaf047SAppaRao Puli { 298e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 299e5aaf047SAppaRao Puli { 3007e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 3017e860f15SJohn Edward Broadbent *subscriptionType, 3027e860f15SJohn Edward Broadbent "SubscriptionType"); 303e5aaf047SAppaRao Puli return; 304e5aaf047SAppaRao Puli } 305b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 306e5aaf047SAppaRao Puli } 307e5aaf047SAppaRao Puli else 308e5aaf047SAppaRao Puli { 309b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 310e5aaf047SAppaRao Puli } 311e5aaf047SAppaRao Puli 312e5aaf047SAppaRao Puli if (protocol != "Redfish") 313e5aaf047SAppaRao Puli { 314e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 315e5aaf047SAppaRao Puli "Protocol"); 316e5aaf047SAppaRao Puli return; 317e5aaf047SAppaRao Puli } 318b52664e2SAppaRao Puli subValue->protocol = protocol; 319e5aaf047SAppaRao Puli 32023a21a1cSEd Tanous if (eventFormatType2) 321e5aaf047SAppaRao Puli { 322e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 323e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 3247e860f15SJohn Edward Broadbent *eventFormatType2) == 3257e860f15SJohn Edward Broadbent supportedEvtFormatTypes.end()) 326e5aaf047SAppaRao Puli { 3277e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 3287e860f15SJohn Edward Broadbent *eventFormatType2, 3297e860f15SJohn Edward Broadbent "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 { 342b52664e2SAppaRao Puli subValue->customText = *context; 343e5aaf047SAppaRao Puli } 344e5aaf047SAppaRao Puli 345e5aaf047SAppaRao Puli if (headers) 346e5aaf047SAppaRao Puli { 347*601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 348*601c71aeSEd Tanous { 349*601c71aeSEd Tanous for (const auto& item : headerChunk.items()) 350*601c71aeSEd Tanous { 351*601c71aeSEd Tanous const std::string* value = 352*601c71aeSEd Tanous item.value().get_ptr<const std::string*>(); 353*601c71aeSEd Tanous if (value == nullptr) 354*601c71aeSEd Tanous { 355*601c71aeSEd Tanous messages::propertyValueFormatError( 356*601c71aeSEd Tanous asyncResp->res, item.value().dump(2, true), 357*601c71aeSEd Tanous "HttpHeaders/" + item.key()); 358*601c71aeSEd Tanous return; 359*601c71aeSEd Tanous } 360*601c71aeSEd Tanous subValue->httpHeaders.set(item.key(), *value); 361*601c71aeSEd Tanous } 362*601c71aeSEd Tanous } 363e5aaf047SAppaRao Puli } 364e5aaf047SAppaRao Puli 365e5aaf047SAppaRao Puli if (regPrefixes) 366e5aaf047SAppaRao Puli { 367e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 368e5aaf047SAppaRao Puli { 369e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 370e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 371e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 372e5aaf047SAppaRao Puli { 3737e860f15SJohn Edward Broadbent messages::propertyValueNotInList( 3747e860f15SJohn Edward Broadbent asyncResp->res, it, "RegistryPrefixes"); 375e5aaf047SAppaRao Puli return; 376e5aaf047SAppaRao Puli } 377e5aaf047SAppaRao Puli } 378b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 379e5aaf047SAppaRao Puli } 380e5aaf047SAppaRao Puli 381e56f254cSSunitha Harish if (resTypes) 382e56f254cSSunitha Harish { 383e56f254cSSunitha Harish for (const std::string& it : *resTypes) 384e56f254cSSunitha Harish { 385e56f254cSSunitha Harish if (std::find(supportedResourceTypes.begin(), 386e56f254cSSunitha Harish supportedResourceTypes.end(), 387e56f254cSSunitha Harish it) == supportedResourceTypes.end()) 388e56f254cSSunitha Harish { 389e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 390e56f254cSSunitha Harish "ResourceTypes"); 391e56f254cSSunitha Harish return; 392e56f254cSSunitha Harish } 393e56f254cSSunitha Harish } 394e56f254cSSunitha Harish subValue->resourceTypes = *resTypes; 395e56f254cSSunitha Harish } 396e56f254cSSunitha Harish 397e5aaf047SAppaRao Puli if (msgIds) 398e5aaf047SAppaRao Puli { 399b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 400b304bd79SP Dheeraj Srujan Kumar 4017e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 4027e860f15SJohn Edward Broadbent // supported prefixes 403b304bd79SP Dheeraj Srujan Kumar if (subValue->registryPrefixes.empty()) 404b304bd79SP Dheeraj Srujan Kumar { 405b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 406b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 407b304bd79SP Dheeraj Srujan Kumar } 408b304bd79SP Dheeraj Srujan Kumar else 409b304bd79SP Dheeraj Srujan Kumar { 410b304bd79SP Dheeraj Srujan Kumar registryPrefix = subValue->registryPrefixes; 411b304bd79SP Dheeraj Srujan Kumar } 412b304bd79SP Dheeraj Srujan Kumar 413b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 414b304bd79SP Dheeraj Srujan Kumar { 415b304bd79SP Dheeraj Srujan Kumar bool validId = false; 416b304bd79SP Dheeraj Srujan Kumar 417b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 418b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 419b304bd79SP Dheeraj Srujan Kumar { 420b304bd79SP Dheeraj Srujan Kumar const boost::beast::span< 421b304bd79SP Dheeraj Srujan Kumar const redfish::message_registries::MessageEntry> 4227e860f15SJohn Edward Broadbent registry = redfish::message_registries:: 4237e860f15SJohn Edward Broadbent getRegistryFromPrefix(it); 424b304bd79SP Dheeraj Srujan Kumar 425b304bd79SP Dheeraj Srujan Kumar if (std::any_of( 426b304bd79SP Dheeraj Srujan Kumar registry.cbegin(), registry.cend(), 4277e860f15SJohn Edward Broadbent [&id](const redfish::message_registries:: 4287e860f15SJohn Edward Broadbent MessageEntry& messageEntry) { 429b304bd79SP Dheeraj Srujan Kumar return !id.compare(messageEntry.first); 430b304bd79SP Dheeraj Srujan Kumar })) 431b304bd79SP Dheeraj Srujan Kumar { 432b304bd79SP Dheeraj Srujan Kumar validId = true; 433b304bd79SP Dheeraj Srujan Kumar break; 434b304bd79SP Dheeraj Srujan Kumar } 435b304bd79SP Dheeraj Srujan Kumar } 436b304bd79SP Dheeraj Srujan Kumar 437b304bd79SP Dheeraj Srujan Kumar if (!validId) 438b304bd79SP Dheeraj Srujan Kumar { 439b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 440b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 441b304bd79SP Dheeraj Srujan Kumar return; 442b304bd79SP Dheeraj Srujan Kumar } 443b304bd79SP Dheeraj Srujan Kumar } 444b304bd79SP Dheeraj Srujan Kumar 445b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 446e5aaf047SAppaRao Puli } 447e5aaf047SAppaRao Puli 448e5aaf047SAppaRao Puli if (retryPolicy) 449e5aaf047SAppaRao Puli { 450e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 451e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 452e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 453e5aaf047SAppaRao Puli { 4547e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 4557e860f15SJohn Edward Broadbent *retryPolicy, 456e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 457e5aaf047SAppaRao Puli return; 458e5aaf047SAppaRao Puli } 459b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 460e5aaf047SAppaRao Puli } 461e5aaf047SAppaRao Puli else 462e5aaf047SAppaRao Puli { 463e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 464b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 465e5aaf047SAppaRao Puli } 466e5aaf047SAppaRao Puli 467144b6318SAppaRao Puli if (mrdJsonArray) 468156d6b00SAppaRao Puli { 469144b6318SAppaRao Puli for (nlohmann::json& mrdObj : *mrdJsonArray) 470144b6318SAppaRao Puli { 471144b6318SAppaRao Puli std::string mrdUri; 4727e860f15SJohn Edward Broadbent if (json_util::getValueFromJsonObject( 4737e860f15SJohn Edward Broadbent mrdObj, "@odata.id", mrdUri)) 474144b6318SAppaRao Puli { 4757e860f15SJohn Edward Broadbent subValue->metricReportDefinitions.emplace_back( 4767e860f15SJohn Edward Broadbent mrdUri); 477144b6318SAppaRao Puli } 478144b6318SAppaRao Puli else 479144b6318SAppaRao Puli { 480144b6318SAppaRao Puli messages::propertyValueFormatError( 48171f52d96SEd Tanous asyncResp->res, 4827e860f15SJohn Edward Broadbent mrdObj.dump( 4837e860f15SJohn Edward Broadbent 2, ' ', true, 48471f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 485144b6318SAppaRao Puli "MetricReportDefinitions"); 486144b6318SAppaRao Puli return; 487144b6318SAppaRao Puli } 488144b6318SAppaRao Puli } 489156d6b00SAppaRao Puli } 490156d6b00SAppaRao Puli 491b52664e2SAppaRao Puli std::string id = 4927e860f15SJohn Edward Broadbent EventServiceManager::getInstance().addSubscription( 4937e860f15SJohn Edward Broadbent subValue); 494b52664e2SAppaRao Puli if (id.empty()) 495e5aaf047SAppaRao Puli { 496e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 497e5aaf047SAppaRao Puli return; 498e5aaf047SAppaRao Puli } 499e5aaf047SAppaRao Puli 500e5aaf047SAppaRao Puli messages::created(asyncResp->res); 501e5aaf047SAppaRao Puli asyncResp->res.addHeader( 502e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 5037e860f15SJohn Edward Broadbent }); 504e5aaf047SAppaRao Puli } 505e5aaf047SAppaRao Puli 5067e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 507e5aaf047SAppaRao Puli { 5089d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 509ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 5107e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 5117e860f15SJohn Edward Broadbent [](const crow::Request&, 5127e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5137e860f15SJohn Edward Broadbent const std::string& param) { 514b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5157e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 516b52664e2SAppaRao Puli if (subValue == nullptr) 517e5aaf047SAppaRao Puli { 5187e860f15SJohn Edward Broadbent asyncResp->res.result( 5197e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 520e5aaf047SAppaRao Puli return; 521e5aaf047SAppaRao Puli } 5227e860f15SJohn Edward Broadbent const std::string& id = param; 523e5aaf047SAppaRao Puli 5248d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 5257e860f15SJohn Edward Broadbent {"@odata.type", 5267e860f15SJohn Edward Broadbent "#EventDestination.v1_7_0.EventDestination"}, 527e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 528e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 529e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 530e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 531e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 5327e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Destination"] = 5337e860f15SJohn Edward Broadbent subValue->destinationUrl; 534b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 535e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 536b52664e2SAppaRao Puli subValue->subscriptionType; 537ad22fefeSEd Tanous asyncResp->res.jsonValue["HttpHeaders"] = 538ad22fefeSEd Tanous nlohmann::json::array(); 5397e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["EventFormatType"] = 5407e860f15SJohn Edward Broadbent subValue->eventFormatType; 541e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 542b52664e2SAppaRao Puli subValue->registryPrefixes; 5437e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ResourceTypes"] = 5447e860f15SJohn Edward Broadbent subValue->resourceTypes; 545e56f254cSSunitha Harish 5467e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MessageIds"] = 5477e860f15SJohn Edward Broadbent subValue->registryMsgIds; 5487e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryPolicy"] = 5497e860f15SJohn Edward Broadbent subValue->retryPolicy; 550144b6318SAppaRao Puli 551144b6318SAppaRao Puli std::vector<nlohmann::json> mrdJsonArray; 552144b6318SAppaRao Puli for (const auto& mdrUri : subValue->metricReportDefinitions) 553144b6318SAppaRao Puli { 554144b6318SAppaRao Puli mrdJsonArray.push_back({{"@odata.id", mdrUri}}); 555144b6318SAppaRao Puli } 5567e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["MetricReportDefinitions"] = 5577e860f15SJohn Edward Broadbent mrdJsonArray; 5587e860f15SJohn Edward Broadbent }); 5599d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 560ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 561ed398213SEd Tanous // ConfigureSelf 5627eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 563ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 564432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 5657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 5667e860f15SJohn Edward Broadbent [](const crow::Request& req, 5677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5687e860f15SJohn Edward Broadbent const std::string& param) { 569b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 5707e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 571b52664e2SAppaRao Puli if (subValue == nullptr) 572e5aaf047SAppaRao Puli { 5737e860f15SJohn Edward Broadbent asyncResp->res.result( 5747e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 575e5aaf047SAppaRao Puli return; 576e5aaf047SAppaRao Puli } 577e5aaf047SAppaRao Puli 578e5aaf047SAppaRao Puli std::optional<std::string> context; 579e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 580e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 581e5aaf047SAppaRao Puli 5827e860f15SJohn Edward Broadbent if (!json_util::readJson(req, asyncResp->res, "Context", 5837e860f15SJohn Edward Broadbent context, "DeliveryRetryPolicy", 5847e860f15SJohn Edward Broadbent retryPolicy, "HttpHeaders", headers)) 585e5aaf047SAppaRao Puli { 586e5aaf047SAppaRao Puli return; 587e5aaf047SAppaRao Puli } 588e5aaf047SAppaRao Puli 589e5aaf047SAppaRao Puli if (context) 590e5aaf047SAppaRao Puli { 591b52664e2SAppaRao Puli subValue->customText = *context; 592e5aaf047SAppaRao Puli } 593e5aaf047SAppaRao Puli 594e5aaf047SAppaRao Puli if (headers) 595e5aaf047SAppaRao Puli { 596*601c71aeSEd Tanous boost::beast::http::fields fields; 597*601c71aeSEd Tanous for (const nlohmann::json& headerChunk : *headers) 598*601c71aeSEd Tanous { 599*601c71aeSEd Tanous for (auto& it : headerChunk.items()) 600*601c71aeSEd Tanous { 601*601c71aeSEd Tanous const std::string* value = 602*601c71aeSEd Tanous it.value().get_ptr<const std::string*>(); 603*601c71aeSEd Tanous if (value == nullptr) 604*601c71aeSEd Tanous { 605*601c71aeSEd Tanous messages::propertyValueFormatError( 606*601c71aeSEd Tanous asyncResp->res, 607*601c71aeSEd Tanous it.value().dump(2, ' ', true), 608*601c71aeSEd Tanous "HttpHeaders/" + it.key()); 609*601c71aeSEd Tanous return; 610*601c71aeSEd Tanous } 611*601c71aeSEd Tanous fields.set(it.key(), *value); 612*601c71aeSEd Tanous } 613*601c71aeSEd Tanous } 614*601c71aeSEd Tanous subValue->httpHeaders = fields; 615e5aaf047SAppaRao Puli } 616e5aaf047SAppaRao Puli 617e5aaf047SAppaRao Puli if (retryPolicy) 618e5aaf047SAppaRao Puli { 619e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 620e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 621e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 622e5aaf047SAppaRao Puli { 6237e860f15SJohn Edward Broadbent messages::propertyValueNotInList(asyncResp->res, 6247e860f15SJohn Edward Broadbent *retryPolicy, 625e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 626e5aaf047SAppaRao Puli return; 627e5aaf047SAppaRao Puli } 628b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 629fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 630e5aaf047SAppaRao Puli } 631e5aaf047SAppaRao Puli 632b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 6337e860f15SJohn Edward Broadbent }); 6349d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 635ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 636ed398213SEd Tanous // ConfigureSelf 6377eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 638ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 639432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 6407e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 6417e860f15SJohn Edward Broadbent [](const crow::Request&, 6427e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6437e860f15SJohn Edward Broadbent const std::string& param) { 6447e860f15SJohn Edward Broadbent if (!EventServiceManager::getInstance().isSubscriptionExist( 6457e860f15SJohn Edward Broadbent param)) 646e5aaf047SAppaRao Puli { 6477e860f15SJohn Edward Broadbent asyncResp->res.result( 6487e860f15SJohn Edward Broadbent boost::beast::http::status::not_found); 649e5aaf047SAppaRao Puli return; 650e5aaf047SAppaRao Puli } 6517e860f15SJohn Edward Broadbent EventServiceManager::getInstance().deleteSubscription(param); 6527e860f15SJohn Edward Broadbent }); 653e5aaf047SAppaRao Puli } 654e5aaf047SAppaRao Puli 655e5aaf047SAppaRao Puli } // namespace redfish 656