xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 1214b7e7d921e331fb1480c7e5d579ffa5811cda)
1b52664e2SAppaRao Puli /*
2b52664e2SAppaRao Puli // Copyright (c) 2020 Intel Corporation
3b52664e2SAppaRao Puli //
4b52664e2SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5b52664e2SAppaRao Puli // you may not use this file except in compliance with the License.
6b52664e2SAppaRao Puli // You may obtain a copy of the License at
7b52664e2SAppaRao Puli //
8b52664e2SAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9b52664e2SAppaRao Puli //
10b52664e2SAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11b52664e2SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12b52664e2SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b52664e2SAppaRao Puli // See the License for the specific language governing permissions and
14b52664e2SAppaRao Puli // limitations under the License.
15b52664e2SAppaRao Puli */
16b52664e2SAppaRao Puli #pragma once
17b52664e2SAppaRao Puli #include "node.hpp"
18b52664e2SAppaRao Puli 
19fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
20b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
21*1214b7e7SGunnar Mills #include <error_messages.hpp>
22*1214b7e7SGunnar Mills #include <http_client.hpp>
23*1214b7e7SGunnar Mills #include <utils/json_utils.hpp>
24*1214b7e7SGunnar Mills 
25b52664e2SAppaRao Puli #include <cstdlib>
26b52664e2SAppaRao Puli #include <ctime>
271bf712bcSAyushi Smriti #include <fstream>
28b52664e2SAppaRao Puli #include <memory>
29b52664e2SAppaRao Puli #include <variant>
30b52664e2SAppaRao Puli 
31b52664e2SAppaRao Puli namespace redfish
32b52664e2SAppaRao Puli {
33156d6b00SAppaRao Puli 
34156d6b00SAppaRao Puli using ReadingsObjType =
35156d6b00SAppaRao Puli     std::vector<std::tuple<std::string, std::string, double, std::string>>;
367d1cc387SAppaRao Puli using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>;
37156d6b00SAppaRao Puli 
38156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
39156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
40156d6b00SAppaRao Puli 
411bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
421bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
431bf712bcSAyushi Smriti 
44b52664e2SAppaRao Puli class Subscription
45b52664e2SAppaRao Puli {
46b52664e2SAppaRao Puli   public:
47b52664e2SAppaRao Puli     std::string id;
48b52664e2SAppaRao Puli     std::string destinationUrl;
49b52664e2SAppaRao Puli     std::string protocol;
50b52664e2SAppaRao Puli     std::string retryPolicy;
51b52664e2SAppaRao Puli     std::string customText;
52b52664e2SAppaRao Puli     std::string eventFormatType;
53b52664e2SAppaRao Puli     std::string subscriptionType;
54b52664e2SAppaRao Puli     std::vector<std::string> registryMsgIds;
55b52664e2SAppaRao Puli     std::vector<std::string> registryPrefixes;
56b52664e2SAppaRao Puli     std::vector<nlohmann::json> httpHeaders; // key-value pair
57156d6b00SAppaRao Puli     std::vector<nlohmann::json> metricReportDefinitions;
58b52664e2SAppaRao Puli 
59b52664e2SAppaRao Puli     Subscription(const Subscription&) = delete;
60b52664e2SAppaRao Puli     Subscription& operator=(const Subscription&) = delete;
61b52664e2SAppaRao Puli     Subscription(Subscription&&) = delete;
62b52664e2SAppaRao Puli     Subscription& operator=(Subscription&&) = delete;
63b52664e2SAppaRao Puli 
64b52664e2SAppaRao Puli     Subscription(const std::string& inHost, const std::string& inPort,
65b52664e2SAppaRao Puli                  const std::string& inPath, const std::string& inUriProto) :
660b4bdd93SAppaRao Puli         eventSeqNum(1),
670b4bdd93SAppaRao Puli         host(inHost), port(inPort), path(inPath), uriProto(inUriProto)
68b52664e2SAppaRao Puli     {
69b52664e2SAppaRao Puli         conn = std::make_shared<crow::HttpClient>(
702a5689a7SAppaRao Puli             crow::connections::systemBus->get_io_context(), host, port, path);
71b52664e2SAppaRao Puli     }
72b52664e2SAppaRao Puli     ~Subscription()
73*1214b7e7SGunnar Mills     {}
74b52664e2SAppaRao Puli 
75b52664e2SAppaRao Puli     void sendEvent(const std::string& msg)
76b52664e2SAppaRao Puli     {
77b52664e2SAppaRao Puli         std::vector<std::pair<std::string, std::string>> reqHeaders;
78b52664e2SAppaRao Puli         for (const auto& header : httpHeaders)
79b52664e2SAppaRao Puli         {
80b52664e2SAppaRao Puli             for (const auto& item : header.items())
81b52664e2SAppaRao Puli             {
82b52664e2SAppaRao Puli                 std::string key = item.key();
83b52664e2SAppaRao Puli                 std::string val = item.value();
84b52664e2SAppaRao Puli                 reqHeaders.emplace_back(std::pair(key, val));
85b52664e2SAppaRao Puli             }
86b52664e2SAppaRao Puli         }
87b52664e2SAppaRao Puli         conn->setHeaders(reqHeaders);
882a5689a7SAppaRao Puli         conn->sendData(msg);
89b52664e2SAppaRao Puli     }
90b52664e2SAppaRao Puli 
910b4bdd93SAppaRao Puli     void sendTestEventLog()
920b4bdd93SAppaRao Puli     {
930b4bdd93SAppaRao Puli         nlohmann::json logEntryArray;
940b4bdd93SAppaRao Puli         logEntryArray.push_back({});
950b4bdd93SAppaRao Puli         nlohmann::json& logEntryJson = logEntryArray.back();
960b4bdd93SAppaRao Puli 
970b4bdd93SAppaRao Puli         logEntryJson = {{"EventId", "TestID"},
980b4bdd93SAppaRao Puli                         {"EventType", "Event"},
990b4bdd93SAppaRao Puli                         {"Severity", "OK"},
1000b4bdd93SAppaRao Puli                         {"Message", "Generated test event"},
1010b4bdd93SAppaRao Puli                         {"MessageId", "OpenBMC.0.1.TestEventLog"},
1020b4bdd93SAppaRao Puli                         {"MessageArgs", nlohmann::json::array()},
1030b4bdd93SAppaRao Puli                         {"EventTimestamp", crow::utility::dateTimeNow()},
1040b4bdd93SAppaRao Puli                         {"Context", customText}};
1050b4bdd93SAppaRao Puli 
1060b4bdd93SAppaRao Puli         nlohmann::json msg = {{"@odata.type", "#Event.v1_4_0.Event"},
1070b4bdd93SAppaRao Puli                               {"Id", std::to_string(eventSeqNum)},
1080b4bdd93SAppaRao Puli                               {"Name", "Event Log"},
1090b4bdd93SAppaRao Puli                               {"Events", logEntryArray}};
1100b4bdd93SAppaRao Puli 
1110b4bdd93SAppaRao Puli         this->sendEvent(msg.dump());
1120b4bdd93SAppaRao Puli         this->eventSeqNum++;
1130b4bdd93SAppaRao Puli     }
1140b4bdd93SAppaRao Puli 
115156d6b00SAppaRao Puli     void filterAndSendReports(const std::string& id,
116156d6b00SAppaRao Puli                               const std::string& readingsTs,
117156d6b00SAppaRao Puli                               const ReadingsObjType& readings)
118156d6b00SAppaRao Puli     {
119156d6b00SAppaRao Puli         std::string metricReportDef =
120156d6b00SAppaRao Puli             "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id;
121156d6b00SAppaRao Puli 
122156d6b00SAppaRao Puli         // Empty list means no filter. Send everything.
123156d6b00SAppaRao Puli         if (metricReportDefinitions.size())
124156d6b00SAppaRao Puli         {
125156d6b00SAppaRao Puli             if (std::find(metricReportDefinitions.begin(),
126156d6b00SAppaRao Puli                           metricReportDefinitions.end(),
127156d6b00SAppaRao Puli                           metricReportDef) == metricReportDefinitions.end())
128156d6b00SAppaRao Puli             {
129156d6b00SAppaRao Puli                 return;
130156d6b00SAppaRao Puli             }
131156d6b00SAppaRao Puli         }
132156d6b00SAppaRao Puli 
133156d6b00SAppaRao Puli         nlohmann::json metricValuesArray = nlohmann::json::array();
134156d6b00SAppaRao Puli         for (const auto& it : readings)
135156d6b00SAppaRao Puli         {
136156d6b00SAppaRao Puli             metricValuesArray.push_back({});
137156d6b00SAppaRao Puli             nlohmann::json& entry = metricValuesArray.back();
138156d6b00SAppaRao Puli 
139156d6b00SAppaRao Puli             entry = {{"MetricId", std::get<0>(it)},
140156d6b00SAppaRao Puli                      {"MetricProperty", std::get<1>(it)},
141156d6b00SAppaRao Puli                      {"MetricValue", std::to_string(std::get<2>(it))},
142156d6b00SAppaRao Puli                      {"Timestamp", std::get<3>(it)}};
143156d6b00SAppaRao Puli         }
144156d6b00SAppaRao Puli 
145156d6b00SAppaRao Puli         nlohmann::json msg = {
146156d6b00SAppaRao Puli             {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id},
147156d6b00SAppaRao Puli             {"@odata.type", "#MetricReport.v1_3_0.MetricReport"},
148156d6b00SAppaRao Puli             {"Id", id},
149156d6b00SAppaRao Puli             {"Name", id},
150156d6b00SAppaRao Puli             {"Timestamp", readingsTs},
151156d6b00SAppaRao Puli             {"MetricReportDefinition", {{"@odata.id", metricReportDef}}},
152156d6b00SAppaRao Puli             {"MetricValues", metricValuesArray}};
153156d6b00SAppaRao Puli 
154156d6b00SAppaRao Puli         this->sendEvent(msg.dump());
155156d6b00SAppaRao Puli     }
156156d6b00SAppaRao Puli 
157b52664e2SAppaRao Puli   private:
1580b4bdd93SAppaRao Puli     uint64_t eventSeqNum;
159b52664e2SAppaRao Puli     std::string host;
160b52664e2SAppaRao Puli     std::string port;
161b52664e2SAppaRao Puli     std::string path;
162b52664e2SAppaRao Puli     std::string uriProto;
163b52664e2SAppaRao Puli     std::shared_ptr<crow::HttpClient> conn;
164b52664e2SAppaRao Puli };
165b52664e2SAppaRao Puli 
1661bf712bcSAyushi Smriti static constexpr const bool defaultEnabledState = true;
1671bf712bcSAyushi Smriti static constexpr const uint32_t defaultRetryAttempts = 3;
1681bf712bcSAyushi Smriti static constexpr const uint32_t defaultRetryInterval = 30;
1691bf712bcSAyushi Smriti static constexpr const char* defaulEventFormatType = "Event";
1701bf712bcSAyushi Smriti static constexpr const char* defaulSubscriptionType = "RedfishEvent";
1711bf712bcSAyushi Smriti static constexpr const char* defaulRetryPolicy = "TerminateAfterRetries";
1721bf712bcSAyushi Smriti 
173b52664e2SAppaRao Puli class EventServiceManager
174b52664e2SAppaRao Puli {
175b52664e2SAppaRao Puli   private:
1767d1cc387SAppaRao Puli     bool serviceEnabled;
1777d1cc387SAppaRao Puli     uint32_t retryAttempts;
1787d1cc387SAppaRao Puli     uint32_t retryTimeoutInterval;
1797d1cc387SAppaRao Puli 
180b52664e2SAppaRao Puli     EventServiceManager(const EventServiceManager&) = delete;
181b52664e2SAppaRao Puli     EventServiceManager& operator=(const EventServiceManager&) = delete;
182b52664e2SAppaRao Puli     EventServiceManager(EventServiceManager&&) = delete;
183b52664e2SAppaRao Puli     EventServiceManager& operator=(EventServiceManager&&) = delete;
184b52664e2SAppaRao Puli 
1857d1cc387SAppaRao Puli     EventServiceManager() :
1867d1cc387SAppaRao Puli         noOfEventLogSubscribers(0), noOfMetricReportSubscribers(0)
187b52664e2SAppaRao Puli     {
1881bf712bcSAyushi Smriti         // Load config from persist store.
1891bf712bcSAyushi Smriti         initConfig();
190b52664e2SAppaRao Puli     }
191b52664e2SAppaRao Puli 
1927d1cc387SAppaRao Puli     size_t noOfEventLogSubscribers;
193156d6b00SAppaRao Puli     size_t noOfMetricReportSubscribers;
194156d6b00SAppaRao Puli     std::shared_ptr<sdbusplus::bus::match::match> matchTelemetryMonitor;
195b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
196b52664e2SAppaRao Puli         subscriptionsMap;
197b52664e2SAppaRao Puli 
198b52664e2SAppaRao Puli   public:
199b52664e2SAppaRao Puli     static EventServiceManager& getInstance()
200b52664e2SAppaRao Puli     {
201b52664e2SAppaRao Puli         static EventServiceManager handler;
202b52664e2SAppaRao Puli         return handler;
203b52664e2SAppaRao Puli     }
204b52664e2SAppaRao Puli 
2051bf712bcSAyushi Smriti     void loadDefaultConfig()
2061bf712bcSAyushi Smriti     {
2071bf712bcSAyushi Smriti         serviceEnabled = defaultEnabledState;
2081bf712bcSAyushi Smriti         retryAttempts = defaultRetryAttempts;
2091bf712bcSAyushi Smriti         retryTimeoutInterval = defaultRetryInterval;
2101bf712bcSAyushi Smriti     }
2111bf712bcSAyushi Smriti 
2121bf712bcSAyushi Smriti     void initConfig()
2131bf712bcSAyushi Smriti     {
2141bf712bcSAyushi Smriti         std::ifstream eventConfigFile(eventServiceFile);
2151bf712bcSAyushi Smriti         if (!eventConfigFile.good())
2161bf712bcSAyushi Smriti         {
2171bf712bcSAyushi Smriti             BMCWEB_LOG_DEBUG << "EventService config not exist";
2181bf712bcSAyushi Smriti             loadDefaultConfig();
2191bf712bcSAyushi Smriti             return;
2201bf712bcSAyushi Smriti         }
2211bf712bcSAyushi Smriti         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
2221bf712bcSAyushi Smriti         if (jsonData.is_discarded())
2231bf712bcSAyushi Smriti         {
2241bf712bcSAyushi Smriti             BMCWEB_LOG_ERROR << "EventService config parse error.";
2251bf712bcSAyushi Smriti             loadDefaultConfig();
2261bf712bcSAyushi Smriti             return;
2271bf712bcSAyushi Smriti         }
2281bf712bcSAyushi Smriti 
2291bf712bcSAyushi Smriti         nlohmann::json jsonConfig;
2301bf712bcSAyushi Smriti         if (json_util::getValueFromJsonObject(jsonData, "Configuration",
2311bf712bcSAyushi Smriti                                               jsonConfig))
2321bf712bcSAyushi Smriti         {
2331bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(jsonConfig, "ServiceEnabled",
2341bf712bcSAyushi Smriti                                                    serviceEnabled))
2351bf712bcSAyushi Smriti             {
2361bf712bcSAyushi Smriti                 serviceEnabled = defaultEnabledState;
2371bf712bcSAyushi Smriti             }
2381bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(
2391bf712bcSAyushi Smriti                     jsonConfig, "DeliveryRetryAttempts", retryAttempts))
2401bf712bcSAyushi Smriti             {
2411bf712bcSAyushi Smriti                 retryAttempts = defaultRetryAttempts;
2421bf712bcSAyushi Smriti             }
2431bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(
2441bf712bcSAyushi Smriti                     jsonConfig, "DeliveryRetryIntervalSeconds",
2451bf712bcSAyushi Smriti                     retryTimeoutInterval))
2461bf712bcSAyushi Smriti             {
2471bf712bcSAyushi Smriti                 retryTimeoutInterval = defaultRetryInterval;
2481bf712bcSAyushi Smriti             }
2491bf712bcSAyushi Smriti         }
2501bf712bcSAyushi Smriti         else
2511bf712bcSAyushi Smriti         {
2521bf712bcSAyushi Smriti             loadDefaultConfig();
2531bf712bcSAyushi Smriti         }
2541bf712bcSAyushi Smriti 
2551bf712bcSAyushi Smriti         nlohmann::json subscriptionsList;
2561bf712bcSAyushi Smriti         if (!json_util::getValueFromJsonObject(jsonData, "Subscriptions",
2571bf712bcSAyushi Smriti                                                subscriptionsList))
2581bf712bcSAyushi Smriti         {
2591bf712bcSAyushi Smriti             BMCWEB_LOG_DEBUG << "EventService: Subscriptions not exist.";
2601bf712bcSAyushi Smriti             return;
2611bf712bcSAyushi Smriti         }
2621bf712bcSAyushi Smriti 
2631bf712bcSAyushi Smriti         for (nlohmann::json& jsonObj : subscriptionsList)
2641bf712bcSAyushi Smriti         {
2651bf712bcSAyushi Smriti             std::string protocol;
2661bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(jsonObj, "Protocol",
2671bf712bcSAyushi Smriti                                                    protocol))
2681bf712bcSAyushi Smriti             {
2691bf712bcSAyushi Smriti                 BMCWEB_LOG_DEBUG << "Invalid subscription Protocol exist.";
2701bf712bcSAyushi Smriti                 continue;
2711bf712bcSAyushi Smriti             }
2721bf712bcSAyushi Smriti             std::string destination;
2731bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(jsonObj, "Destination",
2741bf712bcSAyushi Smriti                                                    destination))
2751bf712bcSAyushi Smriti             {
2761bf712bcSAyushi Smriti                 BMCWEB_LOG_DEBUG << "Invalid subscription destination exist.";
2771bf712bcSAyushi Smriti                 continue;
2781bf712bcSAyushi Smriti             }
2791bf712bcSAyushi Smriti             std::string host;
2801bf712bcSAyushi Smriti             std::string urlProto;
2811bf712bcSAyushi Smriti             std::string port;
2821bf712bcSAyushi Smriti             std::string path;
2831bf712bcSAyushi Smriti             bool status =
2841bf712bcSAyushi Smriti                 validateAndSplitUrl(destination, urlProto, host, port, path);
2851bf712bcSAyushi Smriti 
2861bf712bcSAyushi Smriti             if (!status)
2871bf712bcSAyushi Smriti             {
2881bf712bcSAyushi Smriti                 BMCWEB_LOG_ERROR
2891bf712bcSAyushi Smriti                     << "Failed to validate and split destination url";
2901bf712bcSAyushi Smriti                 continue;
2911bf712bcSAyushi Smriti             }
2921bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
2931bf712bcSAyushi Smriti                 std::make_shared<Subscription>(host, port, path, urlProto);
2941bf712bcSAyushi Smriti 
2951bf712bcSAyushi Smriti             subValue->destinationUrl = destination;
2961bf712bcSAyushi Smriti             subValue->protocol = protocol;
2971bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(
2981bf712bcSAyushi Smriti                     jsonObj, "DeliveryRetryPolicy", subValue->retryPolicy))
2991bf712bcSAyushi Smriti             {
3001bf712bcSAyushi Smriti                 subValue->retryPolicy = defaulRetryPolicy;
3011bf712bcSAyushi Smriti             }
3021bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(jsonObj, "EventFormatType",
3031bf712bcSAyushi Smriti                                                    subValue->eventFormatType))
3041bf712bcSAyushi Smriti             {
3051bf712bcSAyushi Smriti                 subValue->eventFormatType = defaulEventFormatType;
3061bf712bcSAyushi Smriti             }
3071bf712bcSAyushi Smriti             if (!json_util::getValueFromJsonObject(jsonObj, "SubscriptionType",
3081bf712bcSAyushi Smriti                                                    subValue->subscriptionType))
3091bf712bcSAyushi Smriti             {
3101bf712bcSAyushi Smriti                 subValue->subscriptionType = defaulSubscriptionType;
3111bf712bcSAyushi Smriti             }
3121bf712bcSAyushi Smriti 
3131bf712bcSAyushi Smriti             json_util::getValueFromJsonObject(jsonObj, "Context",
3141bf712bcSAyushi Smriti                                               subValue->customText);
3151bf712bcSAyushi Smriti             json_util::getValueFromJsonObject(jsonObj, "MessageIds",
3161bf712bcSAyushi Smriti                                               subValue->registryMsgIds);
3171bf712bcSAyushi Smriti             json_util::getValueFromJsonObject(jsonObj, "RegistryPrefixes",
3181bf712bcSAyushi Smriti                                               subValue->registryPrefixes);
3191bf712bcSAyushi Smriti             json_util::getValueFromJsonObject(jsonObj, "HttpHeaders",
3201bf712bcSAyushi Smriti                                               subValue->httpHeaders);
3211bf712bcSAyushi Smriti             json_util::getValueFromJsonObject(
3221bf712bcSAyushi Smriti                 jsonObj, "MetricReportDefinitions",
3231bf712bcSAyushi Smriti                 subValue->metricReportDefinitions);
3241bf712bcSAyushi Smriti 
3251bf712bcSAyushi Smriti             std::string id = addSubscription(subValue, false);
3261bf712bcSAyushi Smriti             if (id.empty())
3271bf712bcSAyushi Smriti             {
3281bf712bcSAyushi Smriti                 BMCWEB_LOG_ERROR << "Failed to add subscription";
3291bf712bcSAyushi Smriti             }
3301bf712bcSAyushi Smriti         }
3311bf712bcSAyushi Smriti         return;
3321bf712bcSAyushi Smriti     }
3331bf712bcSAyushi Smriti 
334b52664e2SAppaRao Puli     void updateSubscriptionData()
335b52664e2SAppaRao Puli     {
336b52664e2SAppaRao Puli         // Persist the config and subscription data.
3371bf712bcSAyushi Smriti         nlohmann::json jsonData;
3381bf712bcSAyushi Smriti 
3391bf712bcSAyushi Smriti         nlohmann::json& configObj = jsonData["Configuration"];
3401bf712bcSAyushi Smriti         configObj["ServiceEnabled"] = serviceEnabled;
3411bf712bcSAyushi Smriti         configObj["DeliveryRetryAttempts"] = retryAttempts;
3421bf712bcSAyushi Smriti         configObj["DeliveryRetryIntervalSeconds"] = retryTimeoutInterval;
3431bf712bcSAyushi Smriti 
3441bf712bcSAyushi Smriti         nlohmann::json& subListArray = jsonData["Subscriptions"];
3451bf712bcSAyushi Smriti         subListArray = nlohmann::json::array();
3461bf712bcSAyushi Smriti 
3471bf712bcSAyushi Smriti         for (const auto& it : subscriptionsMap)
3481bf712bcSAyushi Smriti         {
3491bf712bcSAyushi Smriti             nlohmann::json entry;
3501bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue = it.second;
3511bf712bcSAyushi Smriti 
3521bf712bcSAyushi Smriti             entry["Context"] = subValue->customText;
3531bf712bcSAyushi Smriti             entry["DeliveryRetryPolicy"] = subValue->retryPolicy;
3541bf712bcSAyushi Smriti             entry["Destination"] = subValue->destinationUrl;
3551bf712bcSAyushi Smriti             entry["EventFormatType"] = subValue->eventFormatType;
3561bf712bcSAyushi Smriti             entry["HttpHeaders"] = subValue->httpHeaders;
3571bf712bcSAyushi Smriti             entry["MessageIds"] = subValue->registryMsgIds;
3581bf712bcSAyushi Smriti             entry["Protocol"] = subValue->protocol;
3591bf712bcSAyushi Smriti             entry["RegistryPrefixes"] = subValue->registryPrefixes;
3601bf712bcSAyushi Smriti             entry["SubscriptionType"] = subValue->subscriptionType;
3611bf712bcSAyushi Smriti             entry["MetricReportDefinitions"] =
3621bf712bcSAyushi Smriti                 subValue->metricReportDefinitions;
3631bf712bcSAyushi Smriti 
3641bf712bcSAyushi Smriti             subListArray.push_back(entry);
3651bf712bcSAyushi Smriti         }
3661bf712bcSAyushi Smriti 
3671bf712bcSAyushi Smriti         const std::string tmpFile(std::string(eventServiceFile) + "_tmp");
3681bf712bcSAyushi Smriti         std::ofstream ofs(tmpFile, std::ios::out);
3691bf712bcSAyushi Smriti         const auto& writeData = jsonData.dump();
3701bf712bcSAyushi Smriti         ofs << writeData;
3711bf712bcSAyushi Smriti         ofs.close();
3721bf712bcSAyushi Smriti 
3731bf712bcSAyushi Smriti         BMCWEB_LOG_DEBUG << "EventService config updated to file.";
3741bf712bcSAyushi Smriti         if (std::rename(tmpFile.c_str(), eventServiceFile) != 0)
3751bf712bcSAyushi Smriti         {
3761bf712bcSAyushi Smriti             BMCWEB_LOG_ERROR << "Error in renaming temporary file: "
3771bf712bcSAyushi Smriti                              << tmpFile.c_str();
3781bf712bcSAyushi Smriti         }
379b52664e2SAppaRao Puli     }
380b52664e2SAppaRao Puli 
3817d1cc387SAppaRao Puli     EventServiceConfig getEventServiceConfig()
3827d1cc387SAppaRao Puli     {
3837d1cc387SAppaRao Puli         return {serviceEnabled, retryAttempts, retryTimeoutInterval};
3847d1cc387SAppaRao Puli     }
3857d1cc387SAppaRao Puli 
3867d1cc387SAppaRao Puli     void setEventServiceConfig(const EventServiceConfig& cfg)
3877d1cc387SAppaRao Puli     {
3887d1cc387SAppaRao Puli         bool updateConfig = false;
3897d1cc387SAppaRao Puli 
3907d1cc387SAppaRao Puli         if (serviceEnabled != std::get<0>(cfg))
3917d1cc387SAppaRao Puli         {
3927d1cc387SAppaRao Puli             serviceEnabled = std::get<0>(cfg);
3937d1cc387SAppaRao Puli             if (serviceEnabled && noOfMetricReportSubscribers)
3947d1cc387SAppaRao Puli             {
3957d1cc387SAppaRao Puli                 registerMetricReportSignal();
3967d1cc387SAppaRao Puli             }
3977d1cc387SAppaRao Puli             else
3987d1cc387SAppaRao Puli             {
3997d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
4007d1cc387SAppaRao Puli             }
4017d1cc387SAppaRao Puli             updateConfig = true;
4027d1cc387SAppaRao Puli         }
4037d1cc387SAppaRao Puli 
4047d1cc387SAppaRao Puli         if (retryAttempts != std::get<1>(cfg))
4057d1cc387SAppaRao Puli         {
4067d1cc387SAppaRao Puli             retryAttempts = std::get<1>(cfg);
4077d1cc387SAppaRao Puli             updateConfig = true;
4087d1cc387SAppaRao Puli         }
4097d1cc387SAppaRao Puli 
4107d1cc387SAppaRao Puli         if (retryTimeoutInterval != std::get<2>(cfg))
4117d1cc387SAppaRao Puli         {
4127d1cc387SAppaRao Puli             retryTimeoutInterval = std::get<2>(cfg);
4137d1cc387SAppaRao Puli             updateConfig = true;
4147d1cc387SAppaRao Puli         }
4157d1cc387SAppaRao Puli 
4167d1cc387SAppaRao Puli         if (updateConfig)
4177d1cc387SAppaRao Puli         {
4187d1cc387SAppaRao Puli             updateSubscriptionData();
4197d1cc387SAppaRao Puli         }
4207d1cc387SAppaRao Puli     }
4217d1cc387SAppaRao Puli 
4227d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
4237d1cc387SAppaRao Puli     {
4247d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
4257d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
4267d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
4277d1cc387SAppaRao Puli         {
4287d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
4297d1cc387SAppaRao Puli             if (entry->eventFormatType == eventFormatType)
4307d1cc387SAppaRao Puli             {
4317d1cc387SAppaRao Puli                 eventLogSubCount++;
4327d1cc387SAppaRao Puli             }
4337d1cc387SAppaRao Puli             else if (entry->eventFormatType == metricReportFormatType)
4347d1cc387SAppaRao Puli             {
4357d1cc387SAppaRao Puli                 metricReportSubCount++;
4367d1cc387SAppaRao Puli             }
4377d1cc387SAppaRao Puli         }
4387d1cc387SAppaRao Puli 
4397d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
4407d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
4417d1cc387SAppaRao Puli         {
4427d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
4437d1cc387SAppaRao Puli             if (noOfMetricReportSubscribers)
4447d1cc387SAppaRao Puli             {
4457d1cc387SAppaRao Puli                 registerMetricReportSignal();
4467d1cc387SAppaRao Puli             }
4477d1cc387SAppaRao Puli             else
4487d1cc387SAppaRao Puli             {
4497d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
4507d1cc387SAppaRao Puli             }
4517d1cc387SAppaRao Puli         }
4527d1cc387SAppaRao Puli     }
4537d1cc387SAppaRao Puli 
454b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
455b52664e2SAppaRao Puli     {
456b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
457b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
458b52664e2SAppaRao Puli         {
459b52664e2SAppaRao Puli             BMCWEB_LOG_ERROR << "No subscription exist with ID:" << id;
460b52664e2SAppaRao Puli             return nullptr;
461b52664e2SAppaRao Puli         }
462b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
463b52664e2SAppaRao Puli         return subValue;
464b52664e2SAppaRao Puli     }
465b52664e2SAppaRao Puli 
4661bf712bcSAyushi Smriti     std::string addSubscription(const std::shared_ptr<Subscription> subValue,
4671bf712bcSAyushi Smriti                                 const bool updateFile = true)
468b52664e2SAppaRao Puli     {
469b52664e2SAppaRao Puli         std::srand(static_cast<uint32_t>(std::time(0)));
470b52664e2SAppaRao Puli         std::string id;
471b52664e2SAppaRao Puli 
472b52664e2SAppaRao Puli         int retry = 3;
473b52664e2SAppaRao Puli         while (retry)
474b52664e2SAppaRao Puli         {
475b52664e2SAppaRao Puli             id = std::to_string(std::rand());
476b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
477b52664e2SAppaRao Puli             if (inserted.second)
478b52664e2SAppaRao Puli             {
479b52664e2SAppaRao Puli                 break;
480b52664e2SAppaRao Puli             }
481b52664e2SAppaRao Puli             --retry;
482b52664e2SAppaRao Puli         };
483b52664e2SAppaRao Puli 
484b52664e2SAppaRao Puli         if (retry <= 0)
485b52664e2SAppaRao Puli         {
486b52664e2SAppaRao Puli             BMCWEB_LOG_ERROR << "Failed to generate random number";
487b52664e2SAppaRao Puli             return std::string("");
488b52664e2SAppaRao Puli         }
489b52664e2SAppaRao Puli 
4907d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4911bf712bcSAyushi Smriti 
4921bf712bcSAyushi Smriti         if (updateFile)
4931bf712bcSAyushi Smriti         {
494b52664e2SAppaRao Puli             updateSubscriptionData();
4951bf712bcSAyushi Smriti         }
496b52664e2SAppaRao Puli         return id;
497b52664e2SAppaRao Puli     }
498b52664e2SAppaRao Puli 
499b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
500b52664e2SAppaRao Puli     {
501b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
502b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
503b52664e2SAppaRao Puli         {
504b52664e2SAppaRao Puli             return false;
505b52664e2SAppaRao Puli         }
506b52664e2SAppaRao Puli         return true;
507b52664e2SAppaRao Puli     }
508b52664e2SAppaRao Puli 
509b52664e2SAppaRao Puli     void deleteSubscription(const std::string& id)
510b52664e2SAppaRao Puli     {
511b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
512b52664e2SAppaRao Puli         if (obj != subscriptionsMap.end())
513b52664e2SAppaRao Puli         {
514b52664e2SAppaRao Puli             subscriptionsMap.erase(obj);
5157d1cc387SAppaRao Puli             updateNoOfSubscribersCount();
516b52664e2SAppaRao Puli             updateSubscriptionData();
517b52664e2SAppaRao Puli         }
518b52664e2SAppaRao Puli     }
519b52664e2SAppaRao Puli 
520b52664e2SAppaRao Puli     size_t getNumberOfSubscriptions()
521b52664e2SAppaRao Puli     {
522b52664e2SAppaRao Puli         return subscriptionsMap.size();
523b52664e2SAppaRao Puli     }
524b52664e2SAppaRao Puli 
525b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
526b52664e2SAppaRao Puli     {
527b52664e2SAppaRao Puli         std::vector<std::string> idList;
528b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
529b52664e2SAppaRao Puli         {
530b52664e2SAppaRao Puli             idList.emplace_back(it.first);
531b52664e2SAppaRao Puli         }
532b52664e2SAppaRao Puli         return idList;
533b52664e2SAppaRao Puli     }
534b52664e2SAppaRao Puli 
535b52664e2SAppaRao Puli     bool isDestinationExist(const std::string& destUrl)
536b52664e2SAppaRao Puli     {
537b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
538b52664e2SAppaRao Puli         {
539b52664e2SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
540b52664e2SAppaRao Puli             if (entry->destinationUrl == destUrl)
541b52664e2SAppaRao Puli             {
542b52664e2SAppaRao Puli                 BMCWEB_LOG_ERROR << "Destination exist already" << destUrl;
543b52664e2SAppaRao Puli                 return true;
544b52664e2SAppaRao Puli             }
545b52664e2SAppaRao Puli         }
546b52664e2SAppaRao Puli         return false;
547b52664e2SAppaRao Puli     }
5480b4bdd93SAppaRao Puli 
5490b4bdd93SAppaRao Puli     void sendTestEventLog()
5500b4bdd93SAppaRao Puli     {
5510b4bdd93SAppaRao Puli         for (const auto& it : this->subscriptionsMap)
5520b4bdd93SAppaRao Puli         {
5530b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5540b4bdd93SAppaRao Puli             entry->sendTestEventLog();
5550b4bdd93SAppaRao Puli         }
5560b4bdd93SAppaRao Puli     }
557e9a14131SAppaRao Puli 
558156d6b00SAppaRao Puli     void getMetricReading(const std::string& service,
559156d6b00SAppaRao Puli                           const std::string& objPath, const std::string& intf)
560156d6b00SAppaRao Puli     {
561156d6b00SAppaRao Puli         std::size_t found = objPath.find_last_of("/");
562156d6b00SAppaRao Puli         if (found == std::string::npos)
563156d6b00SAppaRao Puli         {
564156d6b00SAppaRao Puli             BMCWEB_LOG_DEBUG << "Invalid objPath received";
565156d6b00SAppaRao Puli             return;
566156d6b00SAppaRao Puli         }
567156d6b00SAppaRao Puli 
568156d6b00SAppaRao Puli         std::string idStr = objPath.substr(found + 1);
569156d6b00SAppaRao Puli         if (idStr.empty())
570156d6b00SAppaRao Puli         {
571156d6b00SAppaRao Puli             BMCWEB_LOG_DEBUG << "Invalid ID in objPath";
572156d6b00SAppaRao Puli             return;
573156d6b00SAppaRao Puli         }
574156d6b00SAppaRao Puli 
575156d6b00SAppaRao Puli         crow::connections::systemBus->async_method_call(
576156d6b00SAppaRao Puli             [idStr{std::move(idStr)}](
577156d6b00SAppaRao Puli                 const boost::system::error_code ec,
578156d6b00SAppaRao Puli                 boost::container::flat_map<
579156d6b00SAppaRao Puli                     std::string, std::variant<std::string, ReadingsObjType>>&
580156d6b00SAppaRao Puli                     resp) {
581156d6b00SAppaRao Puli                 if (ec)
582156d6b00SAppaRao Puli                 {
583156d6b00SAppaRao Puli                     BMCWEB_LOG_DEBUG
584156d6b00SAppaRao Puli                         << "D-Bus call failed to GetAll metric readings.";
585156d6b00SAppaRao Puli                     return;
586156d6b00SAppaRao Puli                 }
587156d6b00SAppaRao Puli 
588156d6b00SAppaRao Puli                 const std::string* timestampPtr =
589156d6b00SAppaRao Puli                     std::get_if<std::string>(&resp["Timestamp"]);
590156d6b00SAppaRao Puli                 if (!timestampPtr)
591156d6b00SAppaRao Puli                 {
592156d6b00SAppaRao Puli                     BMCWEB_LOG_DEBUG << "Failed to Get timestamp.";
593156d6b00SAppaRao Puli                     return;
594156d6b00SAppaRao Puli                 }
595156d6b00SAppaRao Puli 
596156d6b00SAppaRao Puli                 ReadingsObjType* readingsPtr =
597156d6b00SAppaRao Puli                     std::get_if<ReadingsObjType>(&resp["Readings"]);
598156d6b00SAppaRao Puli                 if (!readingsPtr)
599156d6b00SAppaRao Puli                 {
600156d6b00SAppaRao Puli                     BMCWEB_LOG_DEBUG << "Failed to Get Readings property.";
601156d6b00SAppaRao Puli                     return;
602156d6b00SAppaRao Puli                 }
603156d6b00SAppaRao Puli 
604156d6b00SAppaRao Puli                 if (!readingsPtr->size())
605156d6b00SAppaRao Puli                 {
606156d6b00SAppaRao Puli                     BMCWEB_LOG_DEBUG << "No metrics report to be transferred";
607156d6b00SAppaRao Puli                     return;
608156d6b00SAppaRao Puli                 }
609156d6b00SAppaRao Puli 
610156d6b00SAppaRao Puli                 for (const auto& it :
611156d6b00SAppaRao Puli                      EventServiceManager::getInstance().subscriptionsMap)
612156d6b00SAppaRao Puli                 {
613156d6b00SAppaRao Puli                     std::shared_ptr<Subscription> entry = it.second;
614156d6b00SAppaRao Puli                     if (entry->eventFormatType == metricReportFormatType)
615156d6b00SAppaRao Puli                     {
616156d6b00SAppaRao Puli                         entry->filterAndSendReports(idStr, *timestampPtr,
617156d6b00SAppaRao Puli                                                     *readingsPtr);
618156d6b00SAppaRao Puli                     }
619156d6b00SAppaRao Puli                 }
620156d6b00SAppaRao Puli             },
621156d6b00SAppaRao Puli             service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
622156d6b00SAppaRao Puli             intf);
623156d6b00SAppaRao Puli     }
624156d6b00SAppaRao Puli 
625156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
626156d6b00SAppaRao Puli     {
6277d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
6287d1cc387SAppaRao Puli         {
629156d6b00SAppaRao Puli             BMCWEB_LOG_DEBUG << "Metrics report signal - Unregister";
630156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
631156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
632156d6b00SAppaRao Puli         }
6337d1cc387SAppaRao Puli     }
634156d6b00SAppaRao Puli 
635156d6b00SAppaRao Puli     void registerMetricReportSignal()
636156d6b00SAppaRao Puli     {
6377d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
638156d6b00SAppaRao Puli         {
6397d1cc387SAppaRao Puli             BMCWEB_LOG_DEBUG << "Not registering metric report signal.";
640156d6b00SAppaRao Puli             return;
641156d6b00SAppaRao Puli         }
642156d6b00SAppaRao Puli 
643156d6b00SAppaRao Puli         BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
644156d6b00SAppaRao Puli         std::string matchStr(
645156d6b00SAppaRao Puli             "type='signal',member='ReportUpdate', "
646156d6b00SAppaRao Puli             "interface='xyz.openbmc_project.MonitoringService.Report'");
647156d6b00SAppaRao Puli 
648156d6b00SAppaRao Puli         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
649156d6b00SAppaRao Puli             *crow::connections::systemBus, matchStr,
650156d6b00SAppaRao Puli             [this](sdbusplus::message::message& msg) {
651156d6b00SAppaRao Puli                 if (msg.is_method_error())
652156d6b00SAppaRao Puli                 {
653156d6b00SAppaRao Puli                     BMCWEB_LOG_ERROR << "TelemetryMonitor Signal error";
654156d6b00SAppaRao Puli                     return;
655156d6b00SAppaRao Puli                 }
656156d6b00SAppaRao Puli 
657156d6b00SAppaRao Puli                 std::string service = msg.get_sender();
658156d6b00SAppaRao Puli                 std::string objPath = msg.get_path();
659156d6b00SAppaRao Puli                 std::string intf = msg.get_interface();
660156d6b00SAppaRao Puli                 getMetricReading(service, objPath, intf);
661156d6b00SAppaRao Puli             });
662156d6b00SAppaRao Puli     }
6631bf712bcSAyushi Smriti 
6641bf712bcSAyushi Smriti     bool validateAndSplitUrl(const std::string& destUrl, std::string& urlProto,
6651bf712bcSAyushi Smriti                              std::string& host, std::string& port,
6661bf712bcSAyushi Smriti                              std::string& path)
6671bf712bcSAyushi Smriti     {
6681bf712bcSAyushi Smriti         // Validate URL using regex expression
6691bf712bcSAyushi Smriti         // Format: <protocol>://<host>:<port>/<path>
6701bf712bcSAyushi Smriti         // protocol: http/https
6711bf712bcSAyushi Smriti         const std::regex urlRegex(
6721bf712bcSAyushi Smriti             "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
6731bf712bcSAyushi Smriti             "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
6741bf712bcSAyushi Smriti         std::cmatch match;
6751bf712bcSAyushi Smriti         if (!std::regex_match(destUrl.c_str(), match, urlRegex))
6761bf712bcSAyushi Smriti         {
6771bf712bcSAyushi Smriti             BMCWEB_LOG_INFO << "Dest. url did not match ";
6781bf712bcSAyushi Smriti             return false;
6791bf712bcSAyushi Smriti         }
6801bf712bcSAyushi Smriti 
6811bf712bcSAyushi Smriti         urlProto = std::string(match[1].first, match[1].second);
6821bf712bcSAyushi Smriti         if (urlProto == "http")
6831bf712bcSAyushi Smriti         {
6841bf712bcSAyushi Smriti #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
6851bf712bcSAyushi Smriti             return false;
6861bf712bcSAyushi Smriti #endif
6871bf712bcSAyushi Smriti         }
6881bf712bcSAyushi Smriti 
6891bf712bcSAyushi Smriti         host = std::string(match[2].first, match[2].second);
6901bf712bcSAyushi Smriti         port = std::string(match[3].first, match[3].second);
6911bf712bcSAyushi Smriti         path = std::string(match[4].first, match[4].second);
6921bf712bcSAyushi Smriti         if (port.empty())
6931bf712bcSAyushi Smriti         {
6941bf712bcSAyushi Smriti             if (urlProto == "http")
6951bf712bcSAyushi Smriti             {
6961bf712bcSAyushi Smriti                 port = "80";
6971bf712bcSAyushi Smriti             }
6981bf712bcSAyushi Smriti             else
6991bf712bcSAyushi Smriti             {
7001bf712bcSAyushi Smriti                 port = "443";
7011bf712bcSAyushi Smriti             }
7021bf712bcSAyushi Smriti         }
7031bf712bcSAyushi Smriti         if (path.empty())
7041bf712bcSAyushi Smriti         {
7051bf712bcSAyushi Smriti             path = "/";
7061bf712bcSAyushi Smriti         }
7071bf712bcSAyushi Smriti         return true;
7081bf712bcSAyushi Smriti     }
70929d2a95bSJames Feist };
710b52664e2SAppaRao Puli 
711b52664e2SAppaRao Puli } // namespace redfish
712