xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 2185ddeac3ed0c49da6399af635f31544e382373)
1b52664e2SAppaRao Puli /*
26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15b52664e2SAppaRao Puli */
16b52664e2SAppaRao Puli #pragma once
173ccb3adbSEd Tanous #include "dbus_utility.hpp"
183ccb3adbSEd Tanous #include "error_messages.hpp"
19b80ba2e4SAlexander Hansen #include "event_log.hpp"
20d3a48a14SEd Tanous #include "event_matches_filter.hpp"
213ccb3adbSEd Tanous #include "event_service_store.hpp"
22*2185ddeaSEd Tanous #include "filesystem_log_watcher.hpp"
23c0353249SWludzik, Jozef #include "metric_report.hpp"
242c6ffdb0SEd Tanous #include "ossl_random.hpp"
253ccb3adbSEd Tanous #include "persistent_data.hpp"
2602c1e29fSAlexander Hansen #include "subscription.hpp"
275b90429aSEd Tanous #include "utils/time_utils.hpp"
287f4eb588SAppaRao Puli 
297f4eb588SAppaRao Puli #include <sys/inotify.h>
30b52664e2SAppaRao Puli 
31fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
32f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
33b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
34ef4c65b7SEd Tanous #include <boost/url/format.hpp>
354a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
36b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp>
371214b7e7SGunnar Mills 
385e44e3d8SAppaRao Puli #include <algorithm>
39b52664e2SAppaRao Puli #include <cstdlib>
40b52664e2SAppaRao Puli #include <ctime>
41a14c9113SEd Tanous #include <format>
421bf712bcSAyushi Smriti #include <fstream>
43b52664e2SAppaRao Puli #include <memory>
44a14c9113SEd Tanous #include <string>
4556ba386dSMyung Bae #include <string_view>
465fe4ef35SMyung Bae #include <utility>
47b52664e2SAppaRao Puli 
48b52664e2SAppaRao Puli namespace redfish
49b52664e2SAppaRao Puli {
50156d6b00SAppaRao Puli 
51156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
52156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
53156d6b00SAppaRao Puli 
541bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
551bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
561bf712bcSAyushi Smriti 
574642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
584642bf8fSGeorge Liu 
59b52664e2SAppaRao Puli class EventServiceManager
60b52664e2SAppaRao Puli {
61b52664e2SAppaRao Puli   private:
62d3a9e084SEd Tanous     bool serviceEnabled = false;
63d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
64d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
657d1cc387SAppaRao Puli 
662558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
679f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
689f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
6959d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
70b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
71b52664e2SAppaRao Puli         subscriptionsMap;
72b52664e2SAppaRao Puli 
739f616dd1SEd Tanous     uint64_t eventId{1};
7496330b99SSunitha Harish 
75f80a87f2SEd Tanous     struct Event
76f80a87f2SEd Tanous     {
77f80a87f2SEd Tanous         std::string id;
78f80a87f2SEd Tanous         nlohmann::json message;
79f80a87f2SEd Tanous     };
80f80a87f2SEd Tanous 
81f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
82f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
83f80a87f2SEd Tanous 
84f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
85f8ca6d79SEd Tanous 
86b52664e2SAppaRao Puli   public:
879f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
889f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
899f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
909f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
91ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
929f616dd1SEd Tanous 
93f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
94b52664e2SAppaRao Puli     {
95f8ca6d79SEd Tanous         // Load config from persist store.
96f8ca6d79SEd Tanous         initConfig();
97f8ca6d79SEd Tanous     }
98f8ca6d79SEd Tanous 
99f8ca6d79SEd Tanous     static EventServiceManager&
100f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
101f8ca6d79SEd Tanous     {
102f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
103b52664e2SAppaRao Puli         return handler;
104b52664e2SAppaRao Puli     }
105b52664e2SAppaRao Puli 
1061bf712bcSAyushi Smriti     void initConfig()
1071bf712bcSAyushi Smriti     {
10828afb49cSJunLin Chen         loadOldBehavior();
1091bf712bcSAyushi Smriti 
11028afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11128afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11228afb49cSJunLin Chen                 .getEventServiceConfig();
1131bf712bcSAyushi Smriti 
11428afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11528afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11628afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1171bf712bcSAyushi Smriti 
11828afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
11928afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1201bf712bcSAyushi Smriti         {
1215fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1225fe4ef35SMyung Bae                 it.second;
1234bbf237fSAppaRao Puli 
1246fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1255fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1261bf712bcSAyushi Smriti 
127a716aa74SEd Tanous             if (!url)
1281bf712bcSAyushi Smriti             {
12962598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13062598e31SEd Tanous                     "Failed to validate and split destination url");
1311bf712bcSAyushi Smriti                 continue;
1321bf712bcSAyushi Smriti             }
1331bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13421a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1355fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
136a0969c70SMyung Bae             subValue->deleter = [id]() {
137a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
138a0969c70SMyung Bae             };
1391bf712bcSAyushi Smriti 
140a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14128afb49cSJunLin Chen 
14228afb49cSJunLin Chen             updateNoOfSubscribersCount();
14328afb49cSJunLin Chen 
14483328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
14583328316SEd Tanous             {
1462558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
14783328316SEd Tanous             }
1482558979cSP Dheeraj Srujan Kumar 
14928afb49cSJunLin Chen             // Update retry configuration.
15028afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
1511bf712bcSAyushi Smriti         }
1521bf712bcSAyushi Smriti     }
1531bf712bcSAyushi Smriti 
15456d2396dSEd Tanous     static void loadOldBehavior()
155b52664e2SAppaRao Puli     {
15628afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15728afb49cSJunLin Chen         if (!eventConfigFile.good())
1581bf712bcSAyushi Smriti         {
15962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
16028afb49cSJunLin Chen             return;
16128afb49cSJunLin Chen         }
16228afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
16328afb49cSJunLin Chen         if (jsonData.is_discarded())
1644bbf237fSAppaRao Puli         {
16562598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16628afb49cSJunLin Chen             return;
16728afb49cSJunLin Chen         }
16828afb49cSJunLin Chen 
1690bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1700bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1710bdda665SEd Tanous         for (const auto& item : *obj)
17228afb49cSJunLin Chen         {
1730bdda665SEd Tanous             if (item.first == "Configuration")
17428afb49cSJunLin Chen             {
17528afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17628afb49cSJunLin Chen                     .getEventServiceConfig()
1770bdda665SEd Tanous                     .fromJson(item.second);
17828afb49cSJunLin Chen             }
1790bdda665SEd Tanous             else if (item.first == "Subscriptions")
18028afb49cSJunLin Chen             {
1810bdda665SEd Tanous                 for (const auto& elem : item.second)
18228afb49cSJunLin Chen                 {
1834b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18428afb49cSJunLin Chen                         newSubscription =
18528afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18628afb49cSJunLin Chen                                                                         true);
1874b712a29SEd Tanous                     if (!newSubscription)
18828afb49cSJunLin Chen                     {
18962598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19062598e31SEd Tanous                                          "from old persistent store");
1914bbf237fSAppaRao Puli                         continue;
1924bbf237fSAppaRao Puli                     }
1934b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1944b712a29SEd Tanous                         *newSubscription;
1951bf712bcSAyushi Smriti 
19628afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19728afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
1981bf712bcSAyushi Smriti 
19928afb49cSJunLin Chen                     std::string id;
2001bf712bcSAyushi Smriti 
20128afb49cSJunLin Chen                     int retry = 3;
202e662eae8SEd Tanous                     while (retry != 0)
2031bf712bcSAyushi Smriti                     {
20428afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20528afb49cSJunLin Chen                         if (gen.error())
2067d1cc387SAppaRao Puli                         {
20728afb49cSJunLin Chen                             retry = 0;
20828afb49cSJunLin Chen                             break;
20928afb49cSJunLin Chen                         }
2104b712a29SEd Tanous                         newSub.id = id;
21128afb49cSJunLin Chen                         auto inserted =
21228afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2135fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2145fe4ef35SMyung Bae                                     id, std::make_shared<
2155fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2165fe4ef35SMyung Bae                                             newSub)));
21728afb49cSJunLin Chen                         if (inserted.second)
21828afb49cSJunLin Chen                         {
21928afb49cSJunLin Chen                             break;
22028afb49cSJunLin Chen                         }
22128afb49cSJunLin Chen                         --retry;
2227d1cc387SAppaRao Puli                     }
2237d1cc387SAppaRao Puli 
22428afb49cSJunLin Chen                     if (retry <= 0)
22528afb49cSJunLin Chen                     {
22662598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22762598e31SEd Tanous                             "Failed to generate random number from old "
22862598e31SEd Tanous                             "persistent store");
22928afb49cSJunLin Chen                         continue;
23028afb49cSJunLin Chen                     }
23128afb49cSJunLin Chen                 }
23228afb49cSJunLin Chen             }
23328afb49cSJunLin Chen 
23428afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2354c521c3cSEd Tanous             std::error_code ec;
2364c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2374c521c3cSEd Tanous             if (ec)
2384c521c3cSEd Tanous             {
2394c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2404c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2414c521c3cSEd Tanous             }
2424c521c3cSEd Tanous             else
2434c521c3cSEd Tanous             {
24462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24528afb49cSJunLin Chen             }
24628afb49cSJunLin Chen         }
2474c521c3cSEd Tanous     }
24828afb49cSJunLin Chen 
2499eb808c1SEd Tanous     void updateSubscriptionData() const
25028afb49cSJunLin Chen     {
25128afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25228afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25428afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25628afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25728afb49cSJunLin Chen 
25828afb49cSJunLin Chen         persistent_data::getConfig().writeData();
25928afb49cSJunLin Chen     }
26028afb49cSJunLin Chen 
26128afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2627d1cc387SAppaRao Puli     {
2637d1cc387SAppaRao Puli         bool updateConfig = false;
264fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2657d1cc387SAppaRao Puli 
26628afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
2677d1cc387SAppaRao Puli         {
26828afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
269e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
2707d1cc387SAppaRao Puli             {
2717d1cc387SAppaRao Puli                 registerMetricReportSignal();
2727d1cc387SAppaRao Puli             }
2737d1cc387SAppaRao Puli             else
2747d1cc387SAppaRao Puli             {
2757d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
2767d1cc387SAppaRao Puli             }
2777d1cc387SAppaRao Puli             updateConfig = true;
2787d1cc387SAppaRao Puli         }
2797d1cc387SAppaRao Puli 
28028afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
2817d1cc387SAppaRao Puli         {
28228afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
2837d1cc387SAppaRao Puli             updateConfig = true;
284fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2857d1cc387SAppaRao Puli         }
2867d1cc387SAppaRao Puli 
28728afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
2887d1cc387SAppaRao Puli         {
28928afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
2907d1cc387SAppaRao Puli             updateConfig = true;
291fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2927d1cc387SAppaRao Puli         }
2937d1cc387SAppaRao Puli 
2947d1cc387SAppaRao Puli         if (updateConfig)
2957d1cc387SAppaRao Puli         {
2967d1cc387SAppaRao Puli             updateSubscriptionData();
2977d1cc387SAppaRao Puli         }
298fe44eb0bSAyushi Smriti 
299fe44eb0bSAyushi Smriti         if (updateRetryCfg)
300fe44eb0bSAyushi Smriti         {
301fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
302fe44eb0bSAyushi Smriti             for (const auto& it :
303fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
304fe44eb0bSAyushi Smriti             {
3055e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3065e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
307fe44eb0bSAyushi Smriti             }
308fe44eb0bSAyushi Smriti         }
3097d1cc387SAppaRao Puli     }
3107d1cc387SAppaRao Puli 
3117d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3127d1cc387SAppaRao Puli     {
3137d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3147d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3157d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3167d1cc387SAppaRao Puli         {
3177d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3185fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3197d1cc387SAppaRao Puli             {
3207d1cc387SAppaRao Puli                 eventLogSubCount++;
3217d1cc387SAppaRao Puli             }
3225fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3237d1cc387SAppaRao Puli             {
3247d1cc387SAppaRao Puli                 metricReportSubCount++;
3257d1cc387SAppaRao Puli             }
3267d1cc387SAppaRao Puli         }
3277d1cc387SAppaRao Puli 
3287d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3297d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
3307d1cc387SAppaRao Puli         {
3317d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
332e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
3337d1cc387SAppaRao Puli             {
3347d1cc387SAppaRao Puli                 registerMetricReportSignal();
3357d1cc387SAppaRao Puli             }
3367d1cc387SAppaRao Puli             else
3377d1cc387SAppaRao Puli             {
3387d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
3397d1cc387SAppaRao Puli             }
3407d1cc387SAppaRao Puli         }
3417d1cc387SAppaRao Puli     }
3427d1cc387SAppaRao Puli 
343b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
344b52664e2SAppaRao Puli     {
345b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
346b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
347b52664e2SAppaRao Puli         {
34862598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
349b52664e2SAppaRao Puli             return nullptr;
350b52664e2SAppaRao Puli         }
351b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
352b52664e2SAppaRao Puli         return subValue;
353b52664e2SAppaRao Puli     }
354b52664e2SAppaRao Puli 
355f80a87f2SEd Tanous     std::string
356f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
357b52664e2SAppaRao Puli     {
358fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
359fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
360fc76b8acSEd Tanous 
361b52664e2SAppaRao Puli         std::string id;
362b52664e2SAppaRao Puli 
363b52664e2SAppaRao Puli         int retry = 3;
364e662eae8SEd Tanous         while (retry != 0)
365b52664e2SAppaRao Puli         {
366fc76b8acSEd Tanous             id = std::to_string(dist(gen));
367fc76b8acSEd Tanous             if (gen.error())
368fc76b8acSEd Tanous             {
369fc76b8acSEd Tanous                 retry = 0;
370fc76b8acSEd Tanous                 break;
371fc76b8acSEd Tanous             }
372b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
373b52664e2SAppaRao Puli             if (inserted.second)
374b52664e2SAppaRao Puli             {
375b52664e2SAppaRao Puli                 break;
376b52664e2SAppaRao Puli             }
377b52664e2SAppaRao Puli             --retry;
37823a21a1cSEd Tanous         }
379b52664e2SAppaRao Puli 
380b52664e2SAppaRao Puli         if (retry <= 0)
381b52664e2SAppaRao Puli         {
38262598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
383abb93cddSEd Tanous             return "";
384b52664e2SAppaRao Puli         }
385b52664e2SAppaRao Puli 
38656ba386dSMyung Bae         // Set Subscription ID for back trace
3875fe4ef35SMyung Bae         subValue->userSub->id = id;
388a14c9113SEd Tanous 
38928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
3905fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
39128afb49cSJunLin Chen 
3927d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
3931bf712bcSAyushi Smriti 
39483328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
39583328316SEd Tanous         {
3962558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
3977f4eb588SAppaRao Puli             {
3982558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
3997f4eb588SAppaRao Puli             }
40083328316SEd Tanous         }
401fe44eb0bSAyushi Smriti         // Update retry configuration.
402fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
403fe44eb0bSAyushi Smriti 
404f80a87f2SEd Tanous         return id;
405f80a87f2SEd Tanous     }
406f80a87f2SEd Tanous 
407f80a87f2SEd Tanous     std::string
408f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
409f80a87f2SEd Tanous                            std::string_view lastEventId)
410f80a87f2SEd Tanous     {
411f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
412f80a87f2SEd Tanous 
413f80a87f2SEd Tanous         if (!lastEventId.empty())
414f80a87f2SEd Tanous         {
415f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
416f80a87f2SEd Tanous                             lastEventId);
417f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
418f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
419f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
420f80a87f2SEd Tanous                                  return event.id == lastEventId;
421f80a87f2SEd Tanous                              });
422f80a87f2SEd Tanous             // Can't find a matching ID
423f80a87f2SEd Tanous             if (lastEvent == messages.end())
424f80a87f2SEd Tanous             {
425f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
426f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4276d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
428f80a87f2SEd Tanous                 lastEvent = messages.begin();
429f80a87f2SEd Tanous             }
430f80a87f2SEd Tanous             else
431f80a87f2SEd Tanous             {
432f80a87f2SEd Tanous                 // Skip the last event the user already has
433f80a87f2SEd Tanous                 lastEvent++;
434f80a87f2SEd Tanous             }
435f80a87f2SEd Tanous 
436f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
437f80a87f2SEd Tanous                      lastEvent;
438f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
439f80a87f2SEd Tanous             {
4406d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
441f80a87f2SEd Tanous             }
442f80a87f2SEd Tanous         }
443f80a87f2SEd Tanous         return id;
444f80a87f2SEd Tanous     }
445f80a87f2SEd Tanous 
446f80a87f2SEd Tanous     std::string
447f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
448f80a87f2SEd Tanous     {
449f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
450a0969c70SMyung Bae         subValue->deleter = [id]() {
451a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
452a0969c70SMyung Bae         };
453f80a87f2SEd Tanous         updateSubscriptionData();
454b52664e2SAppaRao Puli         return id;
455b52664e2SAppaRao Puli     }
456b52664e2SAppaRao Puli 
457b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
458b52664e2SAppaRao Puli     {
459b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
46055f79e6fSEd Tanous         return obj != subscriptionsMap.end();
461b52664e2SAppaRao Puli     }
462b52664e2SAppaRao Puli 
4634b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
464b52664e2SAppaRao Puli     {
465b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
4664b712a29SEd Tanous         if (obj == subscriptionsMap.end())
467b52664e2SAppaRao Puli         {
4684b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
4694b712a29SEd Tanous             return false;
4704b712a29SEd Tanous         }
471b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
4724b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
4734b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
4744b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
4754b712a29SEd Tanous         {
4764b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
4774b712a29SEd Tanous             return true;
4784b712a29SEd Tanous         }
47928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4804b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
4817d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
482b52664e2SAppaRao Puli         updateSubscriptionData();
4834b712a29SEd Tanous 
4844b712a29SEd Tanous         return true;
485b52664e2SAppaRao Puli     }
486b52664e2SAppaRao Puli 
4875e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
4885e44e3d8SAppaRao Puli     {
489bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
4905e44e3d8SAppaRao Puli         {
491bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
4925e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
4935e44e3d8SAppaRao Puli             if (entryIsThisConn)
4945e44e3d8SAppaRao Puli             {
4955e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
4965fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
497bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
4985e44e3d8SAppaRao Puli                 return;
4995e44e3d8SAppaRao Puli             }
500bdbfae2aSEd Tanous             it++;
5015e44e3d8SAppaRao Puli         }
5025e44e3d8SAppaRao Puli     }
5035e44e3d8SAppaRao Puli 
5045e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
505b52664e2SAppaRao Puli     {
506b52664e2SAppaRao Puli         return subscriptionsMap.size();
507b52664e2SAppaRao Puli     }
508b52664e2SAppaRao Puli 
5095e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5105e44e3d8SAppaRao Puli     {
5113544d2a7SEd Tanous         auto size = std::ranges::count_if(
5123544d2a7SEd Tanous             subscriptionsMap,
5135e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5145e44e3d8SAppaRao Puli                    entry) {
5155fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5164b712a29SEd Tanous                         subscriptionTypeSSE);
5175e44e3d8SAppaRao Puli             });
5185e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5195e44e3d8SAppaRao Puli     }
5205e44e3d8SAppaRao Puli 
521b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
522b52664e2SAppaRao Puli     {
523b52664e2SAppaRao Puli         std::vector<std::string> idList;
524b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
525b52664e2SAppaRao Puli         {
526b52664e2SAppaRao Puli             idList.emplace_back(it.first);
527b52664e2SAppaRao Puli         }
528b52664e2SAppaRao Puli         return idList;
529b52664e2SAppaRao Puli     }
530b52664e2SAppaRao Puli 
5316ba8c82eSsunharis_in     bool sendTestEventLog()
5320b4bdd93SAppaRao Puli     {
5335e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5340b4bdd93SAppaRao Puli         {
5350b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5366ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5376ba8c82eSsunharis_in             {
5386ba8c82eSsunharis_in                 return false;
5390b4bdd93SAppaRao Puli             }
5400b4bdd93SAppaRao Puli         }
5416ba8c82eSsunharis_in         return true;
5426ba8c82eSsunharis_in     }
543e9a14131SAppaRao Puli 
544f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
545f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
54696330b99SSunitha Harish     {
547613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
548f80a87f2SEd Tanous 
549613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
550613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
551613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
552613dabeaSEd Tanous 
553f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
554788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
55596330b99SSunitha Harish 
556f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
557f80a87f2SEd Tanous 
558f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
55996330b99SSunitha Harish         {
560f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
5615fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
5625fe4ef35SMyung Bae                                     resourceType))
56396330b99SSunitha Harish             {
564f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
565f80a87f2SEd Tanous                 continue;
56696330b99SSunitha Harish             }
567f80a87f2SEd Tanous 
568f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
569f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
570f80a87f2SEd Tanous 
571613dabeaSEd Tanous             nlohmann::json msgJson;
572613dabeaSEd Tanous 
573613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
574613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
575613dabeaSEd Tanous             msgJson["Id"] = eventId;
576f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
577f52c03c1SCarson Labrado 
578f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
579f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
5806d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
5818ece0e45SEd Tanous             eventId++; // increment the eventId
58296330b99SSunitha Harish         }
58396330b99SSunitha Harish     }
58496330b99SSunitha Harish 
5852558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
5867f4eb588SAppaRao Puli     {
5872558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
5882558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
5892558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
5902558979cSP Dheeraj Srujan Kumar     }
5912558979cSP Dheeraj Srujan Kumar 
5922558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
5932558979cSP Dheeraj Srujan Kumar     {
5942558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
5952558979cSP Dheeraj Srujan Kumar 
5967f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
5977f4eb588SAppaRao Puli         if (!logStream.good())
5987f4eb588SAppaRao Puli         {
59962598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
6007f4eb588SAppaRao Puli             return;
6017f4eb588SAppaRao Puli         }
6027f4eb588SAppaRao Puli         std::string logEntry;
6037f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6047f4eb588SAppaRao Puli         {
6052558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6067f4eb588SAppaRao Puli         }
6077f4eb588SAppaRao Puli     }
6087f4eb588SAppaRao Puli 
6097f4eb588SAppaRao Puli     void readEventLogsFromFile()
6107f4eb588SAppaRao Puli     {
6117f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6127f4eb588SAppaRao Puli         if (!logStream.good())
6137f4eb588SAppaRao Puli         {
61462598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
6157f4eb588SAppaRao Puli             return;
6167f4eb588SAppaRao Puli         }
6177f4eb588SAppaRao Puli 
6187f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
6197f4eb588SAppaRao Puli 
6207f4eb588SAppaRao Puli         std::string logEntry;
6212558979cSP Dheeraj Srujan Kumar 
62203d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
62303d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
62403d4d37cSAlexander Hansen 
6252558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
6262558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
6272558979cSP Dheeraj Srujan Kumar 
6287f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6297f4eb588SAppaRao Puli         {
63003d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
6312558979cSP Dheeraj Srujan Kumar             // Update Pointer position
6322558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6332558979cSP Dheeraj Srujan Kumar 
6342558979cSP Dheeraj Srujan Kumar             std::string idStr;
6352558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
6367f4eb588SAppaRao Puli             {
63703d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
63803d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
63903d4d37cSAlexander Hansen                     logEntry);
6407f4eb588SAppaRao Puli                 continue;
6417f4eb588SAppaRao Puli             }
6427f4eb588SAppaRao Puli 
643e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
6447f4eb588SAppaRao Puli             {
6452558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
6462558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
6472558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
64803d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
64903d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
6507f4eb588SAppaRao Puli                 continue;
6517f4eb588SAppaRao Puli             }
6527f4eb588SAppaRao Puli 
6537f4eb588SAppaRao Puli             std::string timestamp;
6547f4eb588SAppaRao Puli             std::string messageID;
6555e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
6567f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
6577f4eb588SAppaRao Puli                                              messageArgs) != 0)
6587f4eb588SAppaRao Puli             {
65903d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
66003d4d37cSAlexander Hansen                                  logEntry);
6617f4eb588SAppaRao Puli                 continue;
6627f4eb588SAppaRao Puli             }
6637f4eb588SAppaRao Puli 
664f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
6657f4eb588SAppaRao Puli         }
6667f4eb588SAppaRao Puli 
667e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
6682558979cSP Dheeraj Srujan Kumar         {
66962598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
6702558979cSP Dheeraj Srujan Kumar             return;
6712558979cSP Dheeraj Srujan Kumar         }
6722558979cSP Dheeraj Srujan Kumar 
6732558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
6742558979cSP Dheeraj Srujan Kumar         {
6752558979cSP Dheeraj Srujan Kumar             // No Records to send
67662598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
6772558979cSP Dheeraj Srujan Kumar             return;
6782558979cSP Dheeraj Srujan Kumar         }
6792558979cSP Dheeraj Srujan Kumar 
6805e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
6817f4eb588SAppaRao Puli         {
6827f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
6835fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == "Event")
6847f4eb588SAppaRao Puli             {
6857f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
6867f4eb588SAppaRao Puli             }
6877f4eb588SAppaRao Puli         }
6887f4eb588SAppaRao Puli     }
6897f4eb588SAppaRao Puli 
69059d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
691156d6b00SAppaRao Puli     {
69256d2396dSEd Tanous         if (msg.is_method_error())
69356d2396dSEd Tanous         {
69462598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
69556d2396dSEd Tanous             return;
69656d2396dSEd Tanous         }
69756d2396dSEd Tanous 
698c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
699c0353249SWludzik, Jozef         std::string id = path.filename();
700c0353249SWludzik, Jozef         if (id.empty())
701156d6b00SAppaRao Puli         {
70262598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
703156d6b00SAppaRao Puli             return;
704156d6b00SAppaRao Puli         }
705156d6b00SAppaRao Puli 
706c0353249SWludzik, Jozef         std::string interface;
707b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
708c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
709c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
710c0353249SWludzik, Jozef 
711bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
712bd79bce8SPatrick Williams             return x.first == "Readings";
713bd79bce8SPatrick Williams         });
714c0353249SWludzik, Jozef         if (found == props.end())
715156d6b00SAppaRao Puli         {
71662598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
717156d6b00SAppaRao Puli             return;
718156d6b00SAppaRao Puli         }
719156d6b00SAppaRao Puli 
7201e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
7211e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
722e662eae8SEd Tanous         if (readings == nullptr)
7231e1e598dSJonathan Doman         {
72462598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
7251e1e598dSJonathan Doman             return;
7261e1e598dSJonathan Doman         }
7271e1e598dSJonathan Doman 
728156d6b00SAppaRao Puli         for (const auto& it :
729156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
730156d6b00SAppaRao Puli         {
731e05aec50SEd Tanous             Subscription& entry = *it.second;
7325fe4ef35SMyung Bae             if (entry.userSub->eventFormatType == metricReportFormatType)
733156d6b00SAppaRao Puli             {
7341e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
735156d6b00SAppaRao Puli             }
736156d6b00SAppaRao Puli         }
737156d6b00SAppaRao Puli     }
738156d6b00SAppaRao Puli 
739156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
740156d6b00SAppaRao Puli     {
7417d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
7427d1cc387SAppaRao Puli         {
74362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
744156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
745156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
746156d6b00SAppaRao Puli         }
7477d1cc387SAppaRao Puli     }
748156d6b00SAppaRao Puli 
749156d6b00SAppaRao Puli     void registerMetricReportSignal()
750156d6b00SAppaRao Puli     {
7517d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
752156d6b00SAppaRao Puli         {
75362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
754156d6b00SAppaRao Puli             return;
755156d6b00SAppaRao Puli         }
756156d6b00SAppaRao Puli 
75762598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
758c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
759c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
760c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
761156d6b00SAppaRao Puli 
76259d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
76356d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
764156d6b00SAppaRao Puli     }
76523a21a1cSEd Tanous };
766b52664e2SAppaRao Puli 
767b52664e2SAppaRao Puli } // namespace redfish
768