blob: 5cc14cf2d6326479672801b2c172cb88f595a720 [file] [log] [blame]
kasunath37bc0df2022-06-07 12:40:26 -07001#include "rde/external_storer_file.hpp"
2
kasunath37bc0df2022-06-07 12:40:26 -07003#include <boost/uuid/uuid.hpp>
4#include <boost/uuid/uuid_io.hpp>
Patrick Williams5de90612024-02-13 21:31:53 -06005#include <stdplus/print.hpp>
kasunath37bc0df2022-06-07 12:40:26 -07006
Patrick Williams5de90612024-02-13 21:31:53 -06007#include <format>
kasunath37bc0df2022-06-07 12:40:26 -07008#include <fstream>
9#include <string_view>
10
11namespace bios_bmc_smm_error_logger
12{
13namespace rde
14{
15
16bool ExternalStorerFileWriter::createFolder(const std::string& folderPath) const
17{
18 std::filesystem::path path(folderPath);
19 if (!std::filesystem::is_directory(path))
20 {
21 if (!std::filesystem::create_directories(path))
22 {
Patrick Williams5de90612024-02-13 21:31:53 -060023 stdplus::print(stderr, "Failed to create a folder at {}\n",
24 folderPath);
kasunath37bc0df2022-06-07 12:40:26 -070025 return false;
26 }
27 }
28 return true;
29}
30
31bool ExternalStorerFileWriter::createFile(const std::string& folderPath,
32 const nlohmann::json& jsonPdr) const
33{
34 if (!createFolder(folderPath))
35 {
36 return false;
37 }
38 std::filesystem::path path(folderPath);
39 path /= "index.json";
40 // If the file already exist, overwrite it.
41 std::ofstream output(path);
42 output << jsonPdr;
43 output.close();
Patrick Williams5de90612024-02-13 21:31:53 -060044 stdplus::print(stderr, "Created: {}\n", path.string());
kasunath37bc0df2022-06-07 12:40:26 -070045 return true;
46}
47
48ExternalStorerFileInterface::ExternalStorerFileInterface(
Patrick Williamsbea36e22022-07-22 19:26:57 -050049 sdbusplus::bus_t& bus, std::string_view rootPath,
kasunath37bc0df2022-06-07 12:40:26 -070050 std::unique_ptr<FileHandlerInterface> fileHandler) :
Patrick Williams1a643562024-08-16 15:22:05 -040051 rootPath(rootPath), fileHandler(std::move(fileHandler)), logServiceId(""),
kasunatha3b64fb2022-06-15 18:47:18 -070052 cperNotifier(std::make_unique<CperFileNotifierHandler>(bus))
kasunath37bc0df2022-06-07 12:40:26 -070053{}
54
55bool ExternalStorerFileInterface::publishJson(std::string_view jsonStr)
56{
57 nlohmann::json jsonDecoded;
58 try
59 {
60 jsonDecoded = nlohmann::json::parse(jsonStr);
61 }
62 catch (nlohmann::json::parse_error& e)
63 {
Patrick Williams5de90612024-02-13 21:31:53 -060064 stdplus::print(stderr, "JSON parse error: \n{}\n", e.what());
kasunath37bc0df2022-06-07 12:40:26 -070065 return false;
66 }
67
68 // We need to know the type to determine how to process the decoded JSON
69 // output.
70 if (!jsonDecoded.contains("@odata.type"))
71 {
Patrick Williams5de90612024-02-13 21:31:53 -060072 stdplus::print(stderr, "@odata.type field doesn't exist in:\n {}\n",
73 jsonDecoded.dump(4));
kasunath37bc0df2022-06-07 12:40:26 -070074 return false;
75 }
76
77 auto schemaType = getSchemaType(jsonDecoded);
78 if (schemaType == JsonPdrType::logEntry)
79 {
80 return processLogEntry(jsonDecoded);
81 }
82 if (schemaType == JsonPdrType::logService)
83 {
84 return processLogService(jsonDecoded);
85 }
86 return processOtherTypes(jsonDecoded);
87}
88
89JsonPdrType ExternalStorerFileInterface::getSchemaType(
90 const nlohmann::json& jsonSchema) const
91{
92 auto logEntryFound =
93 std::string(jsonSchema["@odata.type"]).find("LogEntry");
94 if (logEntryFound != std::string::npos)
95 {
96 return JsonPdrType::logEntry;
97 }
98
99 auto logServiceFound =
100 std::string(jsonSchema["@odata.type"]).find("LogService");
101 if (logServiceFound != std::string::npos)
102 {
103 return JsonPdrType::logService;
104 }
105
106 return JsonPdrType::other;
107}
108
109bool ExternalStorerFileInterface::processLogEntry(nlohmann::json& logEntry)
110{
111 // TODO: Add policies for LogEntry retention.
112 // https://github.com/openbmc/bios-bmc-smm-error-logger/issues/1.
113 if (logServiceId.empty())
114 {
Patrick Williams5de90612024-02-13 21:31:53 -0600115 stdplus::print(stderr,
116 "First need a LogService PDR with a new UUID.\n");
kasunath37bc0df2022-06-07 12:40:26 -0700117 return false;
118 }
119
120 std::string id = boost::uuids::to_string(randomGen());
kasunatha3b64fb2022-06-15 18:47:18 -0700121 std::string fullPath =
Patrick Williams5de90612024-02-13 21:31:53 -0600122 std::format("{}/redfish/v1/Systems/system/LogServices/{}/Entries/{}",
kasunatha3b64fb2022-06-15 18:47:18 -0700123 rootPath, logServiceId, id);
kasunath37bc0df2022-06-07 12:40:26 -0700124
125 // Populate the "Id" with the UUID we generated.
126 logEntry["Id"] = id;
127 // Remove the @odata.id from the JSON since ExternalStorer will fill it for
128 // a client.
129 logEntry.erase("@odata.id");
130
kasunatha3b64fb2022-06-15 18:47:18 -0700131 if (!fileHandler->createFile(fullPath, logEntry))
132 {
Patrick Williams5de90612024-02-13 21:31:53 -0600133 stdplus::print(stderr,
134 "Failed to create a file for log entry path: {}\n",
135 fullPath);
kasunatha3b64fb2022-06-15 18:47:18 -0700136 return false;
137 }
138
139 cperNotifier->createEntry(fullPath + "/index.json");
140 return true;
kasunath37bc0df2022-06-07 12:40:26 -0700141}
142
143bool ExternalStorerFileInterface::processLogService(
144 const nlohmann::json& logService)
145{
146 if (!logService.contains("@odata.id"))
147 {
Patrick Williams5de90612024-02-13 21:31:53 -0600148 stdplus::print(stderr, "@odata.id field doesn't exist in:\n {}\n",
149 logService.dump(4));
kasunath37bc0df2022-06-07 12:40:26 -0700150 return false;
151 }
152
153 if (!logService.contains("Id"))
154 {
Patrick Williams5de90612024-02-13 21:31:53 -0600155 stdplus::print(stderr, "Id field doesn't exist in:\n {}\n",
156 logService.dump(4));
kasunath37bc0df2022-06-07 12:40:26 -0700157 return false;
158 }
159
160 logServiceId = logService["Id"].get<std::string>();
161
162 if (!createFile(logService["@odata.id"].get<std::string>(), logService))
163 {
Patrick Williams5de90612024-02-13 21:31:53 -0600164 stdplus::print(stderr,
165 "Failed to create LogService index file for:\n{}\n",
166 logService.dump(4));
kasunath37bc0df2022-06-07 12:40:26 -0700167 return false;
168 }
169 // ExternalStorer needs a .../Entries/index.json file with no data.
170 nlohmann::json jEmpty = "{}"_json;
171 return createFile(logService["@odata.id"].get<std::string>() + "/Entries",
172 jEmpty);
173}
174
175bool ExternalStorerFileInterface::processOtherTypes(
176 const nlohmann::json& jsonPdr) const
177{
178 if (!jsonPdr.contains("@odata.id"))
179 {
Patrick Williams5de90612024-02-13 21:31:53 -0600180 stdplus::print(stderr, "@odata.id field doesn't exist in:\n {}\n",
181 jsonPdr.dump(4));
kasunath37bc0df2022-06-07 12:40:26 -0700182 return false;
183 }
184 return createFile(jsonPdr["@odata.id"].get<std::string>(), jsonPdr);
185}
186
187bool ExternalStorerFileInterface::createFile(
188 const std::string& subPath, const nlohmann::json& jsonPdr) const
189{
190 return fileHandler->createFile(rootPath + subPath, jsonPdr);
191}
192
193} // namespace rde
194} // namespace bios_bmc_smm_error_logger