blob: 12601038853694cbed21a2bd37e3412e19374dd3 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanousba9f9a62017-10-11 16:40:35 -07003#pragma once
4
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08005#include "event_service_store.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08006#include "logging.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -07007#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include "sessions.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009// NOLINTNEXTLINE(misc-include-cleaner)
10#include "utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011
Ed Tanousd7857202025-01-28 15:32:26 -080012#include <boost/beast/core/file_base.hpp>
Ed Tanousc282e8b2024-07-01 08:56:34 -070013#include <boost/beast/core/file_posix.hpp>
Ed Tanous601c71a2021-09-08 16:40:12 -070014#include <boost/beast/http/fields.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070015#include <nlohmann/json.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -070016
Ed Tanousd7857202025-01-28 15:32:26 -080017#include <chrono>
Ed Tanousa1700522024-05-20 18:15:36 -070018#include <cstddef>
Ed Tanousd7857202025-01-28 15:32:26 -080019#include <cstdint>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050020#include <filesystem>
Ed Tanousd7857202025-01-28 15:32:26 -080021#include <memory>
22#include <optional>
23#include <string>
Ed Tanousc282e8b2024-07-01 08:56:34 -070024#include <system_error>
Ed Tanousd7857202025-01-28 15:32:26 -080025#include <utility>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace persistent_data
28{
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010029
Ed Tanous52cc1122020-07-18 13:51:21 -070030class ConfigFile
Ed Tanous1abe55e2018-09-05 08:30:59 -070031{
Ed Tanous271584a2019-07-09 16:24:22 -070032 uint64_t jsonRevision = 1;
Ed Tanousc963aa42017-10-27 16:00:19 -070033
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 public:
Ed Tanous13880452025-09-17 09:23:26 -070035 static std::string getStateFile()
36 {
37 // NOLINTNEXTLINE(concurrency-mt-unsafe)
38 const char* stateDir = std::getenv("STATE_DIRECTORY");
39 if (stateDir == nullptr)
40 {
41 stateDir = ".";
42 }
43 return std::string(stateDir) + "/bmcweb_persistent_data.json";
44 }
45
46 static const std::string& filename()
47 {
48 const static std::string fname = getStateFile();
49 return fname;
50 }
Ratan Gupta845cb7d2019-07-12 00:32:25 +053051
Ed Tanous52cc1122020-07-18 13:51:21 -070052 ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 {
54 readData();
Ed Tanousc963aa42017-10-27 16:00:19 -070055 }
Ed Tanousc963aa42017-10-27 16:00:19 -070056
Ed Tanous52cc1122020-07-18 13:51:21 -070057 ~ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 {
Gunnar Mills83cf8182020-11-11 15:37:34 -060059 // Make sure we aren't writing stale sessions
60 persistent_data::SessionStore::getInstance().applySessionTimeouts();
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 if (persistent_data::SessionStore::getInstance().needsWrite())
62 {
63 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010064 }
Ed Tanousc963aa42017-10-27 16:00:19 -070065 }
Ed Tanousc963aa42017-10-27 16:00:19 -070066
Ed Tanousecd6a3a2022-01-07 09:18:40 -080067 ConfigFile(const ConfigFile&) = delete;
68 ConfigFile(ConfigFile&&) = delete;
69 ConfigFile& operator=(const ConfigFile&) = delete;
70 ConfigFile& operator=(ConfigFile&&) = delete;
71
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 // TODO(ed) this should really use protobuf, or some other serialization
73 // library, but adding another dependency is somewhat outside the scope of
74 // this application for the moment
75 void readData()
76 {
Ed Tanousa1700522024-05-20 18:15:36 -070077 boost::beast::file_posix persistentFile;
78 boost::system::error_code ec;
79 const std::string& file = filename();
80 persistentFile.open(file.c_str(), boost::beast::file_mode::read, ec);
Ed Tanous271584a2019-07-09 16:24:22 -070081 uint64_t fileRevision = 0;
Ed Tanousa1700522024-05-20 18:15:36 -070082 if (!ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 {
Ed Tanousa1700522024-05-20 18:15:36 -070084 uint64_t size = persistentFile.size(ec);
85 if (ec)
86 {
87 BMCWEB_LOG_CRITICAL("Can't get filesize of {}", file);
88 return;
89 }
90 std::string str;
91 str.resize(static_cast<size_t>(size), '\0');
92 persistentFile.read(str.data(), str.size(), ec);
93 if (ec)
94 {
95 BMCWEB_LOG_CRITICAL("Failed to read file {}", file);
96 return;
97 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 // call with exceptions disabled
Ed Tanousa1700522024-05-20 18:15:36 -070099 auto data = nlohmann::json::parse(str, nullptr, false);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 if (data.is_discarded())
101 {
Ed Tanous62598e32023-07-17 17:06:25 -0700102 BMCWEB_LOG_ERROR("Error parsing persistent data in json file.");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 }
104 else
105 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700106 const nlohmann::json::object_t* obj =
107 data.get_ptr<nlohmann::json::object_t*>();
108 if (obj == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700110 return;
111 }
112 for (const auto& item : *obj)
113 {
114 if (item.first == "revision")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 {
116 fileRevision = 0;
117
118 const uint64_t* uintPtr =
Ed Tanous0bdda662023-08-03 17:27:34 -0700119 item.second.get_ptr<const uint64_t*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120 if (uintPtr == nullptr)
121 {
Ed Tanous62598e32023-07-17 17:06:25 -0700122 BMCWEB_LOG_ERROR("Failed to read revision flag");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
124 else
125 {
126 fileRevision = *uintPtr;
127 }
128 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700129 else if (item.first == "system_uuid")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 {
131 const std::string* jSystemUuid =
Ed Tanous0bdda662023-08-03 17:27:34 -0700132 item.second.get_ptr<const std::string*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700133 if (jSystemUuid != nullptr)
134 {
135 systemUuid = *jSystemUuid;
136 }
137 }
Corey Ethingtone30d3342025-06-24 11:25:11 -0400138 else if (item.first == "service_identification")
139 {
140 const std::string* jServiceIdentification =
141 item.second.get_ptr<const std::string*>();
142 if (jServiceIdentification != nullptr)
143 {
144 serviceIdentification = *jServiceIdentification;
145 }
146 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700147 else if (item.first == "auth_config")
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100148 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700149 const nlohmann::json::object_t* jObj =
150 item.second
151 .get_ptr<const nlohmann::json::object_t*>();
152 if (jObj == nullptr)
153 {
154 continue;
155 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100156 SessionStore::getInstance()
157 .getAuthMethodsConfig()
Ed Tanous82b286f2025-05-06 13:29:48 -0700158 .fromJson(*jObj);
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100159 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700160 else if (item.first == "sessions")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700162 for (const auto& elem : item.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700164 const nlohmann::json::object_t* jObj =
165 elem.get_ptr<const nlohmann::json::object_t*>();
166 if (jObj == nullptr)
167 {
168 continue;
169 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 std::shared_ptr<UserSession> newSession =
Ed Tanous82b286f2025-05-06 13:29:48 -0700171 UserSession::fromJson(*jObj);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172
173 if (newSession == nullptr)
174 {
Ed Tanous62598e32023-07-17 17:06:25 -0700175 BMCWEB_LOG_ERROR("Problem reading session "
176 "from persistent store");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 continue;
178 }
179
Ed Tanous62598e32023-07-17 17:06:25 -0700180 BMCWEB_LOG_DEBUG("Restored session: {} {} {}",
181 newSession->csrfToken,
182 newSession->uniqueId,
183 newSession->sessionToken);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 SessionStore::getInstance().authTokens.emplace(
185 newSession->sessionToken, newSession);
186 }
187 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700188 else if (item.first == "timeout")
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530189 {
190 const int64_t* jTimeout =
Ed Tanous0bdda662023-08-03 17:27:34 -0700191 item.second.get_ptr<const int64_t*>();
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530192 if (jTimeout == nullptr)
193 {
Ed Tanous62598e32023-07-17 17:06:25 -0700194 BMCWEB_LOG_DEBUG(
195 "Problem reading session timeout value");
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530196 continue;
197 }
198 std::chrono::seconds sessionTimeoutInseconds(*jTimeout);
Ed Tanous62598e32023-07-17 17:06:25 -0700199 BMCWEB_LOG_DEBUG("Restored Session Timeout: {}",
200 sessionTimeoutInseconds.count());
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530201 SessionStore::getInstance().updateSessionTimeout(
202 sessionTimeoutInseconds);
203 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700204 else if (item.first == "eventservice_config")
JunLin Chen28afb492021-02-24 17:13:29 +0800205 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700206 const nlohmann::json::object_t* esobj =
207 item.second
208 .get_ptr<const nlohmann::json::object_t*>();
209 if (esobj == nullptr)
210 {
211 BMCWEB_LOG_DEBUG(
212 "Problem reading EventService value");
213 continue;
214 }
215
JunLin Chen28afb492021-02-24 17:13:29 +0800216 EventServiceStore::getInstance()
217 .getEventServiceConfig()
Ed Tanous0bdda662023-08-03 17:27:34 -0700218 .fromJson(*esobj);
JunLin Chen28afb492021-02-24 17:13:29 +0800219 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700220 else if (item.first == "subscriptions")
JunLin Chen28afb492021-02-24 17:13:29 +0800221 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700222 for (const auto& elem : item.second)
JunLin Chen28afb492021-02-24 17:13:29 +0800223 {
Ed Tanous82b286f2025-05-06 13:29:48 -0700224 const nlohmann::json::object_t* subobj =
225 elem.get_ptr<const nlohmann::json::object_t*>();
226 if (subobj == nullptr)
227 {
228 continue;
229 }
230
Ed Tanous4b712a22023-08-02 12:56:52 -0700231 std::optional<UserSubscription> newSub =
Ed Tanous82b286f2025-05-06 13:29:48 -0700232 UserSubscription::fromJson(*subobj);
JunLin Chen28afb492021-02-24 17:13:29 +0800233
Ed Tanous4b712a22023-08-02 12:56:52 -0700234 if (!newSub)
JunLin Chen28afb492021-02-24 17:13:29 +0800235 {
Myung Bae6136e852025-05-14 07:53:45 -0400236 BMCWEB_LOG_ERROR(
237 "Problem reading subscription from persistent store");
JunLin Chen28afb492021-02-24 17:13:29 +0800238 continue;
239 }
240
Myung Bae6136e852025-05-14 07:53:45 -0400241 std::string id = newSub->id;
242 BMCWEB_LOG_DEBUG("Restored subscription: {} {}", id,
243 newSub->customText);
Ed Tanous4b712a22023-08-02 12:56:52 -0700244
Myung Bae5fe4ef32024-10-19 09:56:02 -0400245 EventServiceStore::getInstance()
246 .subscriptionsConfigMap.emplace(
Myung Bae6136e852025-05-14 07:53:45 -0400247 id, std::make_shared<UserSubscription>(
248 std::move(*newSub)));
JunLin Chen28afb492021-02-24 17:13:29 +0800249 }
250 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 else
252 {
253 // Do nothing in the case of extra fields. We may have
254 // cases where fields are added in the future, and we
255 // want to at least attempt to gracefully support
256 // downgrades in that case, even if we don't officially
257 // support it
258 }
259 }
260 }
261 }
262 bool needWrite = false;
263
264 if (systemUuid.empty())
265 {
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700266 systemUuid = bmcweb::getRandomUUID();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267 needWrite = true;
268 }
269 if (fileRevision < jsonRevision)
270 {
271 needWrite = true;
272 }
273 // write revision changes or system uuid changes immediately
274 if (needWrite)
275 {
276 writeData();
277 }
278 }
279
280 void writeData()
281 {
Ed Tanous13880452025-09-17 09:23:26 -0700282 const std::string& fname = filename();
283 std::filesystem::path path(fname);
Ed Tanousc282e8b2024-07-01 08:56:34 -0700284 path = path.parent_path();
Myung Baed8f8a7d2024-10-23 12:55:08 -0400285 if (!path.empty())
Ed Tanousc282e8b2024-07-01 08:56:34 -0700286 {
Myung Baed8f8a7d2024-10-23 12:55:08 -0400287 std::error_code ecDir;
288 std::filesystem::create_directories(path, ecDir);
289 if (ecDir)
290 {
291 BMCWEB_LOG_CRITICAL("Can't create persistent folders {}",
292 ecDir.message());
293 return;
294 }
Ed Tanousc282e8b2024-07-01 08:56:34 -0700295 }
296 boost::beast::file_posix persistentFile;
297 boost::system::error_code ec;
Ed Tanous13880452025-09-17 09:23:26 -0700298 persistentFile.open(fname.c_str(), boost::beast::file_mode::write, ec);
Ed Tanousc282e8b2024-07-01 08:56:34 -0700299 if (ec)
300 {
301 BMCWEB_LOG_CRITICAL("Unable to store persistent data to file {}",
302 ec.message());
303 return;
304 }
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530305
306 // set the permission of the file to 640
Ed Tanous52cc1122020-07-18 13:51:21 -0700307 std::filesystem::perms permission =
308 std::filesystem::perms::owner_read |
309 std::filesystem::perms::owner_write |
310 std::filesystem::perms::group_read;
Ed Tanous13880452025-09-17 09:23:26 -0700311 std::filesystem::permissions(fname, permission, ec);
Ed Tanousc282e8b2024-07-01 08:56:34 -0700312 if (ec)
313 {
314 BMCWEB_LOG_CRITICAL("Failed to set filesystem permissions {}",
315 ec.message());
316 return;
317 }
Ed Tanous3ce36882024-06-09 10:58:16 -0700318 const AuthConfigMethods& c =
319 SessionStore::getInstance().getAuthMethodsConfig();
JunLin Chen28afb492021-02-24 17:13:29 +0800320 const auto& eventServiceConfig =
321 EventServiceStore::getInstance().getEventServiceConfig();
Ed Tanous14766872022-03-15 10:44:42 -0700322 nlohmann::json::object_t data;
323 nlohmann::json& authConfig = data["auth_config"];
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530324
Ed Tanous14766872022-03-15 10:44:42 -0700325 authConfig["XToken"] = c.xtoken;
326 authConfig["Cookie"] = c.cookie;
327 authConfig["SessionToken"] = c.sessionToken;
328 authConfig["BasicAuth"] = c.basic;
329 authConfig["TLS"] = c.tls;
Ed Tanous3281bcf2024-06-25 16:02:05 -0700330 authConfig["TLSStrict"] = c.tlsStrict;
Malik Akbar Hashemi Rafsanjani86e41a82025-05-06 11:23:32 -0700331 authConfig["MTLSCommonNameParseMode"] =
Ed Tanous3ce36882024-06-09 10:58:16 -0700332 static_cast<int>(c.mTLSCommonNameParsingMode);
JunLin Chen28afb492021-02-24 17:13:29 +0800333
Ed Tanous14766872022-03-15 10:44:42 -0700334 nlohmann::json& eventserviceConfig = data["eventservice_config"];
335 eventserviceConfig["ServiceEnabled"] = eventServiceConfig.enabled;
336 eventserviceConfig["DeliveryRetryAttempts"] =
337 eventServiceConfig.retryAttempts;
338 eventserviceConfig["DeliveryRetryIntervalSeconds"] =
339 eventServiceConfig.retryTimeoutInterval;
340
341 data["system_uuid"] = systemUuid;
Corey Ethingtone30d3342025-06-24 11:25:11 -0400342 data["service_identification"] = serviceIdentification;
Ed Tanous14766872022-03-15 10:44:42 -0700343 data["revision"] = jsonRevision;
344 data["timeout"] = SessionStore::getInstance().getTimeoutInSeconds();
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700345
346 nlohmann::json& sessions = data["sessions"];
347 sessions = nlohmann::json::array();
348 for (const auto& p : SessionStore::getInstance().authTokens)
349 {
Ed Tanous89cda632024-04-16 08:45:54 -0700350 if (p.second->sessionType != persistent_data::SessionType::Basic &&
351 p.second->sessionType !=
352 persistent_data::SessionType::MutualTLS)
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700353 {
Ed Tanous14766872022-03-15 10:44:42 -0700354 nlohmann::json::object_t session;
355 session["unique_id"] = p.second->uniqueId;
356 session["session_token"] = p.second->sessionToken;
357 session["username"] = p.second->username;
358 session["csrf_token"] = p.second->csrfToken;
359 session["client_ip"] = p.second->clientIp;
Ed Tanouse01d0c32023-06-30 13:21:32 -0700360 const std::optional<std::string>& clientId = p.second->clientId;
361 if (clientId)
Ed Tanousbb759e32022-08-02 17:07:54 -0700362 {
Ed Tanouse01d0c32023-06-30 13:21:32 -0700363 session["client_id"] = *clientId;
Ed Tanousbb759e32022-08-02 17:07:54 -0700364 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500365 sessions.emplace_back(std::move(session));
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700366 }
367 }
JunLin Chen28afb492021-02-24 17:13:29 +0800368 nlohmann::json& subscriptions = data["subscriptions"];
369 subscriptions = nlohmann::json::array();
370 for (const auto& it :
371 EventServiceStore::getInstance().subscriptionsConfigMap)
372 {
Myung Bae5fe4ef32024-10-19 09:56:02 -0400373 if (it.second == nullptr)
374 {
375 continue;
376 }
377 const UserSubscription& subValue = *it.second;
wenlitaofbfb7882024-07-12 11:25:00 +0800378 if (subValue.subscriptionType == "SSE")
JunLin Chen28afb492021-02-24 17:13:29 +0800379 {
Ed Tanous62598e32023-07-17 17:06:25 -0700380 BMCWEB_LOG_DEBUG("The subscription type is SSE, so skipping.");
JunLin Chen28afb492021-02-24 17:13:29 +0800381 continue;
382 }
Ed Tanous601c71a2021-09-08 16:40:12 -0700383 nlohmann::json::object_t headers;
384 for (const boost::beast::http::fields::value_type& header :
wenlitaofbfb7882024-07-12 11:25:00 +0800385 subValue.httpHeaders)
Ed Tanous601c71a2021-09-08 16:40:12 -0700386 {
387 // Note, these are technically copies because nlohmann doesn't
388 // support key lookup by std::string_view. At least the
389 // following code can use move
390 // https://github.com/nlohmann/json/issues/1529
391 std::string name(header.name_string());
392 headers[std::move(name)] = header.value();
393 }
394
Ed Tanous14766872022-03-15 10:44:42 -0700395 nlohmann::json::object_t subscription;
396
wenlitaofbfb7882024-07-12 11:25:00 +0800397 subscription["Id"] = subValue.id;
398 subscription["Context"] = subValue.customText;
399 subscription["DeliveryRetryPolicy"] = subValue.retryPolicy;
Myung Bae5064a252024-10-04 09:34:25 -0700400 subscription["SendHeartbeat"] = subValue.sendHeartbeat;
401 subscription["HeartbeatIntervalMinutes"] =
402 subValue.hbIntervalMinutes;
wenlitaofbfb7882024-07-12 11:25:00 +0800403 subscription["Destination"] = subValue.destinationUrl;
404 subscription["EventFormatType"] = subValue.eventFormatType;
Ed Tanous14766872022-03-15 10:44:42 -0700405 subscription["HttpHeaders"] = std::move(headers);
wenlitaofbfb7882024-07-12 11:25:00 +0800406 subscription["MessageIds"] = subValue.registryMsgIds;
407 subscription["Protocol"] = subValue.protocol;
408 subscription["RegistryPrefixes"] = subValue.registryPrefixes;
Ed Tanousa14c9112024-09-04 10:46:47 -0700409 subscription["OriginResources"] = subValue.originResources;
wenlitaofbfb7882024-07-12 11:25:00 +0800410 subscription["ResourceTypes"] = subValue.resourceTypes;
411 subscription["SubscriptionType"] = subValue.subscriptionType;
Ed Tanous14766872022-03-15 10:44:42 -0700412 subscription["MetricReportDefinitions"] =
wenlitaofbfb7882024-07-12 11:25:00 +0800413 subValue.metricReportDefinitions;
Ed Tanous19bb3622024-07-05 10:07:40 -0500414 subscription["VerifyCertificate"] = subValue.verifyCertificate;
Ed Tanous14766872022-03-15 10:44:42 -0700415
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500416 subscriptions.emplace_back(std::move(subscription));
JunLin Chen28afb492021-02-24 17:13:29 +0800417 }
Ed Tanousc282e8b2024-07-01 08:56:34 -0700418 std::string out = nlohmann::json(data).dump(
419 -1, ' ', true, nlohmann::json::error_handler_t::replace);
420 persistentFile.write(out.data(), out.size(), ec);
421 if (ec)
422 {
423 BMCWEB_LOG_ERROR("Failed to write file {}", ec.message());
424 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 }
426
Ed Tanouse05aec52022-01-25 10:28:56 -0800427 std::string systemUuid;
Corey Ethingtone30d3342025-06-24 11:25:11 -0400428 std::string serviceIdentification;
Ed Tanousba9f9a62017-10-11 16:40:35 -0700429};
430
Ed Tanous52cc1122020-07-18 13:51:21 -0700431inline ConfigFile& getConfig()
432{
433 static ConfigFile f;
434 return f;
435}
436
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437} // namespace persistent_data