xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 0b4bdd93c79779913fcfc3641beb5f7f3966f339)
1 /*
2 // Copyright (c) 2020 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 #include "node.hpp"
18 
19 #include <boost/container/flat_map.hpp>
20 #include <cstdlib>
21 #include <ctime>
22 #include <error_messages.hpp>
23 #include <http_client.hpp>
24 #include <memory>
25 #include <utils/json_utils.hpp>
26 #include <variant>
27 
28 namespace redfish
29 {
30 class Subscription
31 {
32   public:
33     std::string id;
34     std::string destinationUrl;
35     std::string protocol;
36     std::string retryPolicy;
37     std::string customText;
38     std::string eventFormatType;
39     std::string subscriptionType;
40     std::vector<std::string> registryMsgIds;
41     std::vector<std::string> registryPrefixes;
42     std::vector<nlohmann::json> httpHeaders; // key-value pair
43 
44     Subscription(const Subscription&) = delete;
45     Subscription& operator=(const Subscription&) = delete;
46     Subscription(Subscription&&) = delete;
47     Subscription& operator=(Subscription&&) = delete;
48 
49     Subscription(const std::string& inHost, const std::string& inPort,
50                  const std::string& inPath, const std::string& inUriProto) :
51         eventSeqNum(1),
52         host(inHost), port(inPort), path(inPath), uriProto(inUriProto)
53     {
54         conn = std::make_shared<crow::HttpClient>(
55             crow::connections::systemBus->get_io_context(), host, port, path);
56     }
57     ~Subscription()
58     {
59     }
60 
61     void sendEvent(const std::string& msg)
62     {
63         std::vector<std::pair<std::string, std::string>> reqHeaders;
64         for (const auto& header : httpHeaders)
65         {
66             for (const auto& item : header.items())
67             {
68                 std::string key = item.key();
69                 std::string val = item.value();
70                 reqHeaders.emplace_back(std::pair(key, val));
71             }
72         }
73         conn->setHeaders(reqHeaders);
74         conn->sendData(msg);
75     }
76 
77     void sendTestEventLog()
78     {
79         nlohmann::json logEntryArray;
80         logEntryArray.push_back({});
81         nlohmann::json& logEntryJson = logEntryArray.back();
82 
83         logEntryJson = {{"EventId", "TestID"},
84                         {"EventType", "Event"},
85                         {"Severity", "OK"},
86                         {"Message", "Generated test event"},
87                         {"MessageId", "OpenBMC.0.1.TestEventLog"},
88                         {"MessageArgs", nlohmann::json::array()},
89                         {"EventTimestamp", crow::utility::dateTimeNow()},
90                         {"Context", customText}};
91 
92         nlohmann::json msg = {{"@odata.type", "#Event.v1_4_0.Event"},
93                               {"Id", std::to_string(eventSeqNum)},
94                               {"Name", "Event Log"},
95                               {"Events", logEntryArray}};
96 
97         this->sendEvent(msg.dump());
98         this->eventSeqNum++;
99     }
100 
101   private:
102     uint64_t eventSeqNum;
103     std::string host;
104     std::string port;
105     std::string path;
106     std::string uriProto;
107     std::shared_ptr<crow::HttpClient> conn;
108 };
109 
110 class EventServiceManager
111 {
112   private:
113     EventServiceManager(const EventServiceManager&) = delete;
114     EventServiceManager& operator=(const EventServiceManager&) = delete;
115     EventServiceManager(EventServiceManager&&) = delete;
116     EventServiceManager& operator=(EventServiceManager&&) = delete;
117 
118     EventServiceManager()
119     {
120         // TODO: Read the persistent data from store and populate.
121         // Populating with default.
122         enabled = true;
123         retryAttempts = 3;
124         retryTimeoutInterval = 30; // seconds
125     }
126 
127     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
128         subscriptionsMap;
129 
130   public:
131     bool enabled;
132     uint32_t retryAttempts;
133     uint32_t retryTimeoutInterval;
134 
135     static EventServiceManager& getInstance()
136     {
137         static EventServiceManager handler;
138         return handler;
139     }
140 
141     void updateSubscriptionData()
142     {
143         // Persist the config and subscription data.
144         // TODO: subscriptionsMap & configData need to be
145         // written to Persist store.
146         return;
147     }
148 
149     std::shared_ptr<Subscription> getSubscription(const std::string& id)
150     {
151         auto obj = subscriptionsMap.find(id);
152         if (obj == subscriptionsMap.end())
153         {
154             BMCWEB_LOG_ERROR << "No subscription exist with ID:" << id;
155             return nullptr;
156         }
157         std::shared_ptr<Subscription> subValue = obj->second;
158         return subValue;
159     }
160 
161     std::string addSubscription(const std::shared_ptr<Subscription> subValue)
162     {
163         std::srand(static_cast<uint32_t>(std::time(0)));
164         std::string id;
165 
166         int retry = 3;
167         while (retry)
168         {
169             id = std::to_string(std::rand());
170             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
171             if (inserted.second)
172             {
173                 break;
174             }
175             --retry;
176         };
177 
178         if (retry <= 0)
179         {
180             BMCWEB_LOG_ERROR << "Failed to generate random number";
181             return std::string("");
182         }
183 
184         updateSubscriptionData();
185         return id;
186     }
187 
188     bool isSubscriptionExist(const std::string& id)
189     {
190         auto obj = subscriptionsMap.find(id);
191         if (obj == subscriptionsMap.end())
192         {
193             return false;
194         }
195         return true;
196     }
197 
198     void deleteSubscription(const std::string& id)
199     {
200         auto obj = subscriptionsMap.find(id);
201         if (obj != subscriptionsMap.end())
202         {
203             subscriptionsMap.erase(obj);
204             updateSubscriptionData();
205         }
206     }
207 
208     size_t getNumberOfSubscriptions()
209     {
210         return subscriptionsMap.size();
211     }
212 
213     std::vector<std::string> getAllIDs()
214     {
215         std::vector<std::string> idList;
216         for (const auto& it : subscriptionsMap)
217         {
218             idList.emplace_back(it.first);
219         }
220         return idList;
221     }
222 
223     bool isDestinationExist(const std::string& destUrl)
224     {
225         for (const auto& it : subscriptionsMap)
226         {
227             std::shared_ptr<Subscription> entry = it.second;
228             if (entry->destinationUrl == destUrl)
229             {
230                 BMCWEB_LOG_ERROR << "Destination exist already" << destUrl;
231                 return true;
232             }
233         }
234         return false;
235     }
236 
237     void sendTestEventLog()
238     {
239         for (const auto& it : this->subscriptionsMap)
240         {
241             std::shared_ptr<Subscription> entry = it.second;
242             entry->sendTestEventLog();
243         }
244     }
245 };
246 
247 } // namespace redfish
248