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 19e5aaf047SAppaRao Puli namespace redfish 20e5aaf047SAppaRao Puli { 21e5aaf047SAppaRao Puli 22156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 23156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 24e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 25e5aaf047SAppaRao Puli "Base", "OpenBMC", "Task"}; 26e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 27e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 28e5aaf047SAppaRao Puli 29e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20; 30e5aaf047SAppaRao Puli 31e5aaf047SAppaRao Puli class EventService : public Node 32e5aaf047SAppaRao Puli { 33e5aaf047SAppaRao Puli public: 34e5aaf047SAppaRao Puli EventService(CrowApp& app) : Node(app, "/redfish/v1/EventService/") 35e5aaf047SAppaRao Puli { 36e5aaf047SAppaRao Puli entityPrivileges = { 37e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 38e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 39e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 40e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 41e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 42e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 43e5aaf047SAppaRao Puli } 44e5aaf047SAppaRao Puli 45e5aaf047SAppaRao Puli private: 46e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 47e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 48e5aaf047SAppaRao Puli { 49e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 50e5aaf047SAppaRao Puli res.jsonValue = { 51e5aaf047SAppaRao Puli {"@odata.type", "#EventService.v1_5_0.EventService"}, 52e5aaf047SAppaRao Puli {"Id", "EventService"}, 53e5aaf047SAppaRao Puli {"Name", "Event Service"}, 54e5aaf047SAppaRao Puli {"ServerSentEventUri", 55e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/SSE"}, 56e5aaf047SAppaRao Puli {"Subscriptions", 57e5aaf047SAppaRao Puli {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}}, 580b4bdd93SAppaRao Puli {"Actions", 590b4bdd93SAppaRao Puli {{"#EventService.SubmitTestEvent", 600b4bdd93SAppaRao Puli {{"target", "/redfish/v1/EventService/Actions/" 610b4bdd93SAppaRao Puli "EventService.SubmitTestEvent"}}}}}, 62e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService"}}; 63e5aaf047SAppaRao Puli 647d1cc387SAppaRao Puli const auto& [enabled, retryAttempts, retryTimeoutInterval] = 657d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 667d1cc387SAppaRao Puli 677d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 687d1cc387SAppaRao Puli (enabled ? "Enabled" : "Disabled"); 697d1cc387SAppaRao Puli asyncResp->res.jsonValue["ServiceEnabled"] = enabled; 707d1cc387SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryAttempts"] = retryAttempts; 71e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 727d1cc387SAppaRao Puli retryTimeoutInterval; 73e5aaf047SAppaRao Puli asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes; 74e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 75e5aaf047SAppaRao Puli } 76e5aaf047SAppaRao Puli 77e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 78e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 79e5aaf047SAppaRao Puli { 80e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 81e5aaf047SAppaRao Puli 82e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 83e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 84e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 85e5aaf047SAppaRao Puli 86e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "ServiceEnabled", serviceEnabled, 87e5aaf047SAppaRao Puli "DeliveryRetryAttempts", retryAttemps, 88e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", retryInterval)) 89e5aaf047SAppaRao Puli { 90e5aaf047SAppaRao Puli return; 91e5aaf047SAppaRao Puli } 92e5aaf047SAppaRao Puli 937d1cc387SAppaRao Puli auto [enabled, retryCount, retryTimeoutInterval] = 947d1cc387SAppaRao Puli EventServiceManager::getInstance().getEventServiceConfig(); 957d1cc387SAppaRao Puli 96e5aaf047SAppaRao Puli if (serviceEnabled) 97e5aaf047SAppaRao Puli { 987d1cc387SAppaRao Puli enabled = *serviceEnabled; 99e5aaf047SAppaRao Puli } 100e5aaf047SAppaRao Puli 101e5aaf047SAppaRao Puli if (retryAttemps) 102e5aaf047SAppaRao Puli { 103e5aaf047SAppaRao Puli // Supported range [1-3] 104e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 105e5aaf047SAppaRao Puli { 106e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 107e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 108e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 109e5aaf047SAppaRao Puli } 110e5aaf047SAppaRao Puli else 111e5aaf047SAppaRao Puli { 1127d1cc387SAppaRao Puli retryCount = *retryAttemps; 113e5aaf047SAppaRao Puli } 114e5aaf047SAppaRao Puli } 115e5aaf047SAppaRao Puli 116e5aaf047SAppaRao Puli if (retryInterval) 117e5aaf047SAppaRao Puli { 118e5aaf047SAppaRao Puli // Supported range [30 - 180] 119e5aaf047SAppaRao Puli if ((*retryInterval < 30) || (*retryInterval > 180)) 120e5aaf047SAppaRao Puli { 121e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 122e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 123e5aaf047SAppaRao Puli "DeliveryRetryIntervalSeconds", "[30-180]"); 124e5aaf047SAppaRao Puli } 125e5aaf047SAppaRao Puli else 126e5aaf047SAppaRao Puli { 1277d1cc387SAppaRao Puli retryTimeoutInterval = *retryInterval; 128e5aaf047SAppaRao Puli } 129e5aaf047SAppaRao Puli } 130e5aaf047SAppaRao Puli 1317d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 1327d1cc387SAppaRao Puli std::make_tuple(enabled, retryCount, retryTimeoutInterval)); 133e5aaf047SAppaRao Puli } 134e5aaf047SAppaRao Puli }; 135e5aaf047SAppaRao Puli 1360b4bdd93SAppaRao Puli class SubmitTestEvent : public Node 1370b4bdd93SAppaRao Puli { 1380b4bdd93SAppaRao Puli public: 1390b4bdd93SAppaRao Puli SubmitTestEvent(CrowApp& app) : 1400b4bdd93SAppaRao Puli Node(app, 1410b4bdd93SAppaRao Puli "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 1420b4bdd93SAppaRao Puli { 1430b4bdd93SAppaRao Puli entityPrivileges = { 1440b4bdd93SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 1450b4bdd93SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 1460b4bdd93SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1470b4bdd93SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1480b4bdd93SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1490b4bdd93SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 1500b4bdd93SAppaRao Puli } 1510b4bdd93SAppaRao Puli 1520b4bdd93SAppaRao Puli private: 1530b4bdd93SAppaRao Puli void doPost(crow::Response& res, const crow::Request& req, 1540b4bdd93SAppaRao Puli const std::vector<std::string>& params) override 1550b4bdd93SAppaRao Puli { 1560b4bdd93SAppaRao Puli EventServiceManager::getInstance().sendTestEventLog(); 1570b4bdd93SAppaRao Puli res.result(boost::beast::http::status::no_content); 1580b4bdd93SAppaRao Puli res.end(); 1590b4bdd93SAppaRao Puli } 1600b4bdd93SAppaRao Puli }; 1610b4bdd93SAppaRao Puli 162e5aaf047SAppaRao Puli class EventDestinationCollection : public Node 163e5aaf047SAppaRao Puli { 164e5aaf047SAppaRao Puli public: 165e5aaf047SAppaRao Puli EventDestinationCollection(CrowApp& app) : 166e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/") 167e5aaf047SAppaRao Puli { 168e5aaf047SAppaRao Puli entityPrivileges = { 169e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 170e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 171e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 172e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 173e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 174e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 175e5aaf047SAppaRao Puli } 176e5aaf047SAppaRao Puli 177e5aaf047SAppaRao Puli private: 178e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 179e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 180e5aaf047SAppaRao Puli { 181e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 182e5aaf047SAppaRao Puli 183e5aaf047SAppaRao Puli res.jsonValue = { 184e5aaf047SAppaRao Puli {"@odata.type", 185e5aaf047SAppaRao Puli "#EventDestinationCollection.EventDestinationCollection"}, 186e5aaf047SAppaRao Puli {"@odata.id", "/redfish/v1/EventService/Subscriptions"}, 187e5aaf047SAppaRao Puli {"Name", "Event Destination Collections"}}; 188e5aaf047SAppaRao Puli 189e5aaf047SAppaRao Puli nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 190e5aaf047SAppaRao Puli 191b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 192b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 193b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 194b52664e2SAppaRao Puli asyncResp->res.jsonValue["Members@odata.count"] = 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 } 202e5aaf047SAppaRao Puli } 203e5aaf047SAppaRao Puli 204e5aaf047SAppaRao Puli void doPost(crow::Response& res, const crow::Request& req, 205e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 206e5aaf047SAppaRao Puli { 207e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 208e5aaf047SAppaRao Puli 209b52664e2SAppaRao Puli if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 210b52664e2SAppaRao Puli maxNoOfSubscriptions) 211e5aaf047SAppaRao Puli { 212e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 213e5aaf047SAppaRao Puli return; 214e5aaf047SAppaRao Puli } 215e5aaf047SAppaRao Puli std::string destUrl; 216e5aaf047SAppaRao Puli std::string protocol; 217e5aaf047SAppaRao Puli std::optional<std::string> context; 218e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 219e5aaf047SAppaRao Puli std::optional<std::string> eventFormatType; 220e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 221e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 222e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 223e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 224156d6b00SAppaRao Puli std::optional<std::vector<nlohmann::json>> metricReportDefinitions; 225e5aaf047SAppaRao Puli 226e5aaf047SAppaRao Puli if (!json_util::readJson( 227e5aaf047SAppaRao Puli req, res, "Destination", destUrl, "Context", context, 228e5aaf047SAppaRao Puli "Protocol", protocol, "SubscriptionType", subscriptionType, 229e5aaf047SAppaRao Puli "EventFormatType", eventFormatType, "HttpHeaders", headers, 230e5aaf047SAppaRao Puli "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, 231156d6b00SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", 232156d6b00SAppaRao Puli metricReportDefinitions)) 233e5aaf047SAppaRao Puli { 234e5aaf047SAppaRao Puli return; 235e5aaf047SAppaRao Puli } 236e5aaf047SAppaRao Puli 237e5aaf047SAppaRao Puli // Validate the URL using regex expression 238b52664e2SAppaRao Puli // Format: <protocol>://<host>:<port>/<uri> 239b52664e2SAppaRao Puli // protocol: http/https 240b52664e2SAppaRao Puli // host: Exclude ' ', ':', '#', '?' 241b52664e2SAppaRao Puli // port: Empty or numeric value with ':' seperator. 242b52664e2SAppaRao Puli // uri: Start with '/' and Exclude '#', ' ' 243b52664e2SAppaRao Puli // Can include query params(ex: '/event?test=1') 244b52664e2SAppaRao Puli // TODO: Need to validate hostname extensively(as per rfc) 245b52664e2SAppaRao Puli const std::regex urlRegex( 246b52664e2SAppaRao Puli "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/" 247b52664e2SAppaRao Puli "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)"); 248b52664e2SAppaRao Puli std::cmatch match; 249b52664e2SAppaRao Puli if (!std::regex_match(destUrl.c_str(), match, urlRegex)) 250e5aaf047SAppaRao Puli { 251e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 252e5aaf047SAppaRao Puli "Destination"); 253e5aaf047SAppaRao Puli return; 254e5aaf047SAppaRao Puli } 255b52664e2SAppaRao Puli 256b52664e2SAppaRao Puli std::string uriProto = std::string(match[1].first, match[1].second); 257b52664e2SAppaRao Puli if (uriProto == "http") 258b52664e2SAppaRao Puli { 259b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING 260b52664e2SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 261b52664e2SAppaRao Puli "Destination"); 262b52664e2SAppaRao Puli return; 263b52664e2SAppaRao Puli #endif 264b52664e2SAppaRao Puli } 265b52664e2SAppaRao Puli 266b52664e2SAppaRao Puli std::string host = std::string(match[2].first, match[2].second); 267b52664e2SAppaRao Puli std::string port = std::string(match[3].first, match[3].second); 268b52664e2SAppaRao Puli std::string path = std::string(match[4].first, match[4].second); 269b52664e2SAppaRao Puli if (port.empty()) 270b52664e2SAppaRao Puli { 271b52664e2SAppaRao Puli if (uriProto == "http") 272b52664e2SAppaRao Puli { 273b52664e2SAppaRao Puli port = "80"; 274b52664e2SAppaRao Puli } 275b52664e2SAppaRao Puli else 276b52664e2SAppaRao Puli { 277b52664e2SAppaRao Puli port = "443"; 278b52664e2SAppaRao Puli } 279b52664e2SAppaRao Puli } 280b52664e2SAppaRao Puli if (path.empty()) 281b52664e2SAppaRao Puli { 282b52664e2SAppaRao Puli path = "/"; 283b52664e2SAppaRao Puli } 284b52664e2SAppaRao Puli 285b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 286b52664e2SAppaRao Puli std::make_shared<Subscription>(host, port, path, uriProto); 287b52664e2SAppaRao Puli 288b52664e2SAppaRao Puli subValue->destinationUrl = destUrl; 289e5aaf047SAppaRao Puli 290e5aaf047SAppaRao Puli if (subscriptionType) 291e5aaf047SAppaRao Puli { 292e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 293e5aaf047SAppaRao Puli { 294e5aaf047SAppaRao Puli messages::propertyValueNotInList( 295e5aaf047SAppaRao Puli asyncResp->res, *subscriptionType, "SubscriptionType"); 296e5aaf047SAppaRao Puli return; 297e5aaf047SAppaRao Puli } 298b52664e2SAppaRao Puli subValue->subscriptionType = *subscriptionType; 299e5aaf047SAppaRao Puli } 300e5aaf047SAppaRao Puli else 301e5aaf047SAppaRao Puli { 302b52664e2SAppaRao Puli subValue->subscriptionType = "RedfishEvent"; // Default 303e5aaf047SAppaRao Puli } 304e5aaf047SAppaRao Puli 305e5aaf047SAppaRao Puli if (protocol != "Redfish") 306e5aaf047SAppaRao Puli { 307e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 308e5aaf047SAppaRao Puli "Protocol"); 309e5aaf047SAppaRao Puli return; 310e5aaf047SAppaRao Puli } 311b52664e2SAppaRao Puli subValue->protocol = protocol; 312e5aaf047SAppaRao Puli 313e5aaf047SAppaRao Puli if (eventFormatType) 314e5aaf047SAppaRao Puli { 315e5aaf047SAppaRao Puli if (std::find(supportedEvtFormatTypes.begin(), 316e5aaf047SAppaRao Puli supportedEvtFormatTypes.end(), 317e5aaf047SAppaRao Puli *eventFormatType) == supportedEvtFormatTypes.end()) 318e5aaf047SAppaRao Puli { 319e5aaf047SAppaRao Puli messages::propertyValueNotInList( 320e5aaf047SAppaRao Puli asyncResp->res, *eventFormatType, "EventFormatType"); 321e5aaf047SAppaRao Puli return; 322e5aaf047SAppaRao Puli } 323b52664e2SAppaRao Puli subValue->eventFormatType = *eventFormatType; 324e5aaf047SAppaRao Puli } 325e5aaf047SAppaRao Puli else 326e5aaf047SAppaRao Puli { 327e5aaf047SAppaRao Puli // If not specified, use default "Event" 328b52664e2SAppaRao Puli subValue->eventFormatType.assign({"Event"}); 329e5aaf047SAppaRao Puli } 330e5aaf047SAppaRao Puli 331e5aaf047SAppaRao Puli if (context) 332e5aaf047SAppaRao Puli { 333b52664e2SAppaRao Puli subValue->customText = *context; 334e5aaf047SAppaRao Puli } 335e5aaf047SAppaRao Puli 336e5aaf047SAppaRao Puli if (headers) 337e5aaf047SAppaRao Puli { 338b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 339e5aaf047SAppaRao Puli } 340e5aaf047SAppaRao Puli 341e5aaf047SAppaRao Puli if (regPrefixes) 342e5aaf047SAppaRao Puli { 343e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 344e5aaf047SAppaRao Puli { 345e5aaf047SAppaRao Puli if (std::find(supportedRegPrefixes.begin(), 346e5aaf047SAppaRao Puli supportedRegPrefixes.end(), 347e5aaf047SAppaRao Puli it) == supportedRegPrefixes.end()) 348e5aaf047SAppaRao Puli { 349e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, it, 350e5aaf047SAppaRao Puli "RegistryPrefixes"); 351e5aaf047SAppaRao Puli return; 352e5aaf047SAppaRao Puli } 353e5aaf047SAppaRao Puli } 354b52664e2SAppaRao Puli subValue->registryPrefixes = *regPrefixes; 355e5aaf047SAppaRao Puli } 356e5aaf047SAppaRao Puli 357e5aaf047SAppaRao Puli if (msgIds) 358e5aaf047SAppaRao Puli { 359e5aaf047SAppaRao Puli // Do we need to loop-up MessageRegistry and validate 360e5aaf047SAppaRao Puli // data for authenticity??? Not mandate, i believe. 361b52664e2SAppaRao Puli subValue->registryMsgIds = *msgIds; 362e5aaf047SAppaRao Puli } 363e5aaf047SAppaRao Puli 364e5aaf047SAppaRao Puli if (retryPolicy) 365e5aaf047SAppaRao Puli { 366e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 367e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 368e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 369e5aaf047SAppaRao Puli { 370e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 371e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 372e5aaf047SAppaRao Puli return; 373e5aaf047SAppaRao Puli } 374b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 375e5aaf047SAppaRao Puli } 376e5aaf047SAppaRao Puli else 377e5aaf047SAppaRao Puli { 378e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 379b52664e2SAppaRao Puli subValue->retryPolicy = "TerminateAfterRetries"; 380e5aaf047SAppaRao Puli } 381e5aaf047SAppaRao Puli 382156d6b00SAppaRao Puli if (metricReportDefinitions) 383156d6b00SAppaRao Puli { 384156d6b00SAppaRao Puli subValue->metricReportDefinitions = *metricReportDefinitions; 385156d6b00SAppaRao Puli } 386156d6b00SAppaRao Puli 387b52664e2SAppaRao Puli std::string id = 388b52664e2SAppaRao Puli EventServiceManager::getInstance().addSubscription(subValue); 389b52664e2SAppaRao Puli if (id.empty()) 390e5aaf047SAppaRao Puli { 391e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 392e5aaf047SAppaRao Puli return; 393e5aaf047SAppaRao Puli } 394e5aaf047SAppaRao Puli 395e5aaf047SAppaRao Puli messages::created(asyncResp->res); 396e5aaf047SAppaRao Puli asyncResp->res.addHeader( 397e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 398e5aaf047SAppaRao Puli } 399e5aaf047SAppaRao Puli }; 400e5aaf047SAppaRao Puli 401e5aaf047SAppaRao Puli class EventDestination : public Node 402e5aaf047SAppaRao Puli { 403e5aaf047SAppaRao Puli public: 404e5aaf047SAppaRao Puli EventDestination(CrowApp& app) : 405e5aaf047SAppaRao Puli Node(app, "/redfish/v1/EventService/Subscriptions/<str>/", 406e5aaf047SAppaRao Puli std::string()) 407e5aaf047SAppaRao Puli { 408e5aaf047SAppaRao Puli entityPrivileges = { 409e5aaf047SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 410e5aaf047SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 411e5aaf047SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 412e5aaf047SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 413e5aaf047SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 414e5aaf047SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 415e5aaf047SAppaRao Puli } 416e5aaf047SAppaRao Puli 417e5aaf047SAppaRao Puli private: 418e5aaf047SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 419e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 420e5aaf047SAppaRao Puli { 421e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 422e5aaf047SAppaRao Puli if (params.size() != 1) 423e5aaf047SAppaRao Puli { 424e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 425e5aaf047SAppaRao Puli return; 426e5aaf047SAppaRao Puli } 427e5aaf047SAppaRao Puli 428b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 429b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 430b52664e2SAppaRao Puli if (subValue == nullptr) 431e5aaf047SAppaRao Puli { 432e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 433e5aaf047SAppaRao Puli res.end(); 434e5aaf047SAppaRao Puli return; 435e5aaf047SAppaRao Puli } 436b52664e2SAppaRao Puli const std::string& id = params[0]; 437e5aaf047SAppaRao Puli 438e5aaf047SAppaRao Puli res.jsonValue = { 439e5aaf047SAppaRao Puli {"@odata.type", "#EventDestination.v1_7_0.EventDestination"}, 440e5aaf047SAppaRao Puli {"Protocol", "Redfish"}}; 441e5aaf047SAppaRao Puli asyncResp->res.jsonValue["@odata.id"] = 442e5aaf047SAppaRao Puli "/redfish/v1/EventService/Subscriptions/" + id; 443e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Id"] = id; 444e5aaf047SAppaRao Puli asyncResp->res.jsonValue["Name"] = "Event Destination " + id; 445b52664e2SAppaRao Puli asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl; 446b52664e2SAppaRao Puli asyncResp->res.jsonValue["Context"] = subValue->customText; 447e5aaf047SAppaRao Puli asyncResp->res.jsonValue["SubscriptionType"] = 448b52664e2SAppaRao Puli subValue->subscriptionType; 449b52664e2SAppaRao Puli asyncResp->res.jsonValue["HttpHeaders"] = subValue->httpHeaders; 450b52664e2SAppaRao Puli asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType; 451e5aaf047SAppaRao Puli asyncResp->res.jsonValue["RegistryPrefixes"] = 452b52664e2SAppaRao Puli subValue->registryPrefixes; 453b52664e2SAppaRao Puli asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; 454b52664e2SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; 455156d6b00SAppaRao Puli asyncResp->res.jsonValue["MetricReportDefinitions"] = 456156d6b00SAppaRao Puli subValue->metricReportDefinitions; 457e5aaf047SAppaRao Puli } 458e5aaf047SAppaRao Puli 459e5aaf047SAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 460e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 461e5aaf047SAppaRao Puli { 462e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 463e5aaf047SAppaRao Puli if (params.size() != 1) 464e5aaf047SAppaRao Puli { 465e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 466e5aaf047SAppaRao Puli return; 467e5aaf047SAppaRao Puli } 468e5aaf047SAppaRao Puli 469b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 470b52664e2SAppaRao Puli EventServiceManager::getInstance().getSubscription(params[0]); 471b52664e2SAppaRao Puli if (subValue == nullptr) 472e5aaf047SAppaRao Puli { 473e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 474e5aaf047SAppaRao Puli res.end(); 475e5aaf047SAppaRao Puli return; 476e5aaf047SAppaRao Puli } 477e5aaf047SAppaRao Puli 478e5aaf047SAppaRao Puli std::optional<std::string> context; 479e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 480e5aaf047SAppaRao Puli std::optional<std::vector<nlohmann::json>> headers; 481e5aaf047SAppaRao Puli 482e5aaf047SAppaRao Puli if (!json_util::readJson(req, res, "Context", context, 483e5aaf047SAppaRao Puli "DeliveryRetryPolicy", retryPolicy, 484e5aaf047SAppaRao Puli "HttpHeaders", headers)) 485e5aaf047SAppaRao Puli { 486e5aaf047SAppaRao Puli return; 487e5aaf047SAppaRao Puli } 488e5aaf047SAppaRao Puli 489e5aaf047SAppaRao Puli if (context) 490e5aaf047SAppaRao Puli { 491b52664e2SAppaRao Puli subValue->customText = *context; 492e5aaf047SAppaRao Puli } 493e5aaf047SAppaRao Puli 494e5aaf047SAppaRao Puli if (headers) 495e5aaf047SAppaRao Puli { 496b52664e2SAppaRao Puli subValue->httpHeaders = *headers; 497e5aaf047SAppaRao Puli } 498e5aaf047SAppaRao Puli 499e5aaf047SAppaRao Puli if (retryPolicy) 500e5aaf047SAppaRao Puli { 501e5aaf047SAppaRao Puli if (std::find(supportedRetryPolicies.begin(), 502e5aaf047SAppaRao Puli supportedRetryPolicies.end(), 503e5aaf047SAppaRao Puli *retryPolicy) == supportedRetryPolicies.end()) 504e5aaf047SAppaRao Puli { 505e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, *retryPolicy, 506e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 507e5aaf047SAppaRao Puli return; 508e5aaf047SAppaRao Puli } 509b52664e2SAppaRao Puli subValue->retryPolicy = *retryPolicy; 510*fe44eb0bSAyushi Smriti subValue->updateRetryPolicy(); 511e5aaf047SAppaRao Puli } 512e5aaf047SAppaRao Puli 513b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 514e5aaf047SAppaRao Puli } 515e5aaf047SAppaRao Puli 516e5aaf047SAppaRao Puli void doDelete(crow::Response& res, const crow::Request& req, 517e5aaf047SAppaRao Puli const std::vector<std::string>& params) override 518e5aaf047SAppaRao Puli { 519e5aaf047SAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 520e5aaf047SAppaRao Puli 521e5aaf047SAppaRao Puli if (params.size() != 1) 522e5aaf047SAppaRao Puli { 523e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 524e5aaf047SAppaRao Puli return; 525e5aaf047SAppaRao Puli } 526e5aaf047SAppaRao Puli 527b52664e2SAppaRao Puli if (!EventServiceManager::getInstance().isSubscriptionExist(params[0])) 528e5aaf047SAppaRao Puli { 529e5aaf047SAppaRao Puli res.result(boost::beast::http::status::not_found); 530e5aaf047SAppaRao Puli res.end(); 531e5aaf047SAppaRao Puli return; 532e5aaf047SAppaRao Puli } 533b52664e2SAppaRao Puli EventServiceManager::getInstance().deleteSubscription(params[0]); 534e5aaf047SAppaRao Puli } 535e5aaf047SAppaRao Puli }; 536e5aaf047SAppaRao Puli 537e5aaf047SAppaRao Puli } // namespace redfish 538