1*75dac00eSOliver Brewka // SPDX-FileCopyrightText: Copyright OpenBMC Authors
2*75dac00eSOliver Brewka // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
3*75dac00eSOliver Brewka #pragma once
4*75dac00eSOliver Brewka
5*75dac00eSOliver Brewka #include "bmcweb_config.h"
6*75dac00eSOliver Brewka
7*75dac00eSOliver Brewka #include "app.hpp"
8*75dac00eSOliver Brewka #include "async_resp.hpp"
9*75dac00eSOliver Brewka #include "dbus_utility.hpp"
10*75dac00eSOliver Brewka #include "error_messages.hpp"
11*75dac00eSOliver Brewka #include "http_request.hpp"
12*75dac00eSOliver Brewka #include "http_response.hpp"
13*75dac00eSOliver Brewka #include "logging.hpp"
14*75dac00eSOliver Brewka #include "query.hpp"
15*75dac00eSOliver Brewka #include "registries.hpp"
16*75dac00eSOliver Brewka #include "registries/privilege_registry.hpp"
17*75dac00eSOliver Brewka #include "str_utility.hpp"
18*75dac00eSOliver Brewka #include "utils/query_param.hpp"
19*75dac00eSOliver Brewka
20*75dac00eSOliver Brewka #include <asm-generic/errno.h>
21*75dac00eSOliver Brewka #include <systemd/sd-bus.h>
22*75dac00eSOliver Brewka #include <unistd.h>
23*75dac00eSOliver Brewka
24*75dac00eSOliver Brewka #include <boost/beast/http/field.hpp>
25*75dac00eSOliver Brewka #include <boost/beast/http/status.hpp>
26*75dac00eSOliver Brewka #include <boost/beast/http/verb.hpp>
27*75dac00eSOliver Brewka #include <boost/system/linux_error.hpp>
28*75dac00eSOliver Brewka #include <boost/url/format.hpp>
29*75dac00eSOliver Brewka #include <boost/url/url.hpp>
30*75dac00eSOliver Brewka #include <sdbusplus/message.hpp>
31*75dac00eSOliver Brewka #include <sdbusplus/message/native_types.hpp>
32*75dac00eSOliver Brewka #include <sdbusplus/unpack_properties.hpp>
33*75dac00eSOliver Brewka
34*75dac00eSOliver Brewka #include <algorithm>
35*75dac00eSOliver Brewka #include <cstddef>
36*75dac00eSOliver Brewka #include <cstdint>
37*75dac00eSOliver Brewka #include <cstdio>
38*75dac00eSOliver Brewka #include <ctime>
39*75dac00eSOliver Brewka #include <filesystem>
40*75dac00eSOliver Brewka #include <format>
41*75dac00eSOliver Brewka #include <fstream>
42*75dac00eSOliver Brewka #include <functional>
43*75dac00eSOliver Brewka #include <iomanip>
44*75dac00eSOliver Brewka #include <iterator>
45*75dac00eSOliver Brewka #include <memory>
46*75dac00eSOliver Brewka #include <optional>
47*75dac00eSOliver Brewka #include <span>
48*75dac00eSOliver Brewka #include <sstream>
49*75dac00eSOliver Brewka #include <string>
50*75dac00eSOliver Brewka #include <string_view>
51*75dac00eSOliver Brewka #include <system_error>
52*75dac00eSOliver Brewka #include <utility>
53*75dac00eSOliver Brewka #include <vector>
54*75dac00eSOliver Brewka
55*75dac00eSOliver Brewka namespace redfish
56*75dac00eSOliver Brewka {
57*75dac00eSOliver Brewka
getRedfishLogFiles(std::vector<std::filesystem::path> & redfishLogFiles)58*75dac00eSOliver Brewka inline bool getRedfishLogFiles(
59*75dac00eSOliver Brewka std::vector<std::filesystem::path>& redfishLogFiles)
60*75dac00eSOliver Brewka {
61*75dac00eSOliver Brewka static const std::filesystem::path redfishLogDir = "/var/log";
62*75dac00eSOliver Brewka static const std::string redfishLogFilename = "redfish";
63*75dac00eSOliver Brewka
64*75dac00eSOliver Brewka // Loop through the directory looking for redfish log files
65*75dac00eSOliver Brewka for (const std::filesystem::directory_entry& dirEnt :
66*75dac00eSOliver Brewka std::filesystem::directory_iterator(redfishLogDir))
67*75dac00eSOliver Brewka {
68*75dac00eSOliver Brewka // If we find a redfish log file, save the path
69*75dac00eSOliver Brewka std::string filename = dirEnt.path().filename();
70*75dac00eSOliver Brewka if (filename.starts_with(redfishLogFilename))
71*75dac00eSOliver Brewka {
72*75dac00eSOliver Brewka redfishLogFiles.emplace_back(redfishLogDir / filename);
73*75dac00eSOliver Brewka }
74*75dac00eSOliver Brewka }
75*75dac00eSOliver Brewka // As the log files rotate, they are appended with a ".#" that is higher for
76*75dac00eSOliver Brewka // the older logs. Since we don't expect more than 10 log files, we
77*75dac00eSOliver Brewka // can just sort the list to get them in order from newest to oldest
78*75dac00eSOliver Brewka std::ranges::sort(redfishLogFiles);
79*75dac00eSOliver Brewka
80*75dac00eSOliver Brewka return !redfishLogFiles.empty();
81*75dac00eSOliver Brewka }
82*75dac00eSOliver Brewka
getUniqueEntryID(const std::string & logEntry,std::string & entryID,const bool firstEntry=true)83*75dac00eSOliver Brewka inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
84*75dac00eSOliver Brewka const bool firstEntry = true)
85*75dac00eSOliver Brewka {
86*75dac00eSOliver Brewka static time_t prevTs = 0;
87*75dac00eSOliver Brewka static int index = 0;
88*75dac00eSOliver Brewka if (firstEntry)
89*75dac00eSOliver Brewka {
90*75dac00eSOliver Brewka prevTs = 0;
91*75dac00eSOliver Brewka }
92*75dac00eSOliver Brewka
93*75dac00eSOliver Brewka // Get the entry timestamp
94*75dac00eSOliver Brewka std::time_t curTs = 0;
95*75dac00eSOliver Brewka std::tm timeStruct = {};
96*75dac00eSOliver Brewka std::istringstream entryStream(logEntry);
97*75dac00eSOliver Brewka if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
98*75dac00eSOliver Brewka {
99*75dac00eSOliver Brewka curTs = std::mktime(&timeStruct);
100*75dac00eSOliver Brewka }
101*75dac00eSOliver Brewka // If the timestamp isn't unique, increment the index
102*75dac00eSOliver Brewka if (curTs == prevTs)
103*75dac00eSOliver Brewka {
104*75dac00eSOliver Brewka index++;
105*75dac00eSOliver Brewka }
106*75dac00eSOliver Brewka else
107*75dac00eSOliver Brewka {
108*75dac00eSOliver Brewka // Otherwise, reset it
109*75dac00eSOliver Brewka index = 0;
110*75dac00eSOliver Brewka }
111*75dac00eSOliver Brewka // Save the timestamp
112*75dac00eSOliver Brewka prevTs = curTs;
113*75dac00eSOliver Brewka
114*75dac00eSOliver Brewka entryID = std::to_string(curTs);
115*75dac00eSOliver Brewka if (index > 0)
116*75dac00eSOliver Brewka {
117*75dac00eSOliver Brewka entryID += "_" + std::to_string(index);
118*75dac00eSOliver Brewka }
119*75dac00eSOliver Brewka return true;
120*75dac00eSOliver Brewka }
121*75dac00eSOliver Brewka
122*75dac00eSOliver Brewka enum class LogParseError
123*75dac00eSOliver Brewka {
124*75dac00eSOliver Brewka success,
125*75dac00eSOliver Brewka parseFailed,
126*75dac00eSOliver Brewka messageIdNotInRegistry,
127*75dac00eSOliver Brewka };
128*75dac00eSOliver Brewka
fillEventLogEntryJson(const std::string & logEntryID,const std::string & logEntry,nlohmann::json::object_t & logEntryJson)129*75dac00eSOliver Brewka static LogParseError fillEventLogEntryJson(
130*75dac00eSOliver Brewka const std::string& logEntryID, const std::string& logEntry,
131*75dac00eSOliver Brewka nlohmann::json::object_t& logEntryJson)
132*75dac00eSOliver Brewka {
133*75dac00eSOliver Brewka // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
134*75dac00eSOliver Brewka // First get the Timestamp
135*75dac00eSOliver Brewka size_t space = logEntry.find_first_of(' ');
136*75dac00eSOliver Brewka if (space == std::string::npos)
137*75dac00eSOliver Brewka {
138*75dac00eSOliver Brewka return LogParseError::parseFailed;
139*75dac00eSOliver Brewka }
140*75dac00eSOliver Brewka std::string timestamp = logEntry.substr(0, space);
141*75dac00eSOliver Brewka // Then get the log contents
142*75dac00eSOliver Brewka size_t entryStart = logEntry.find_first_not_of(' ', space);
143*75dac00eSOliver Brewka if (entryStart == std::string::npos)
144*75dac00eSOliver Brewka {
145*75dac00eSOliver Brewka return LogParseError::parseFailed;
146*75dac00eSOliver Brewka }
147*75dac00eSOliver Brewka std::string_view entry(logEntry);
148*75dac00eSOliver Brewka entry.remove_prefix(entryStart);
149*75dac00eSOliver Brewka // Use split to separate the entry into its fields
150*75dac00eSOliver Brewka std::vector<std::string> logEntryFields;
151*75dac00eSOliver Brewka bmcweb::split(logEntryFields, entry, ',');
152*75dac00eSOliver Brewka // We need at least a MessageId to be valid
153*75dac00eSOliver Brewka auto logEntryIter = logEntryFields.begin();
154*75dac00eSOliver Brewka if (logEntryIter == logEntryFields.end())
155*75dac00eSOliver Brewka {
156*75dac00eSOliver Brewka return LogParseError::parseFailed;
157*75dac00eSOliver Brewka }
158*75dac00eSOliver Brewka std::string& messageID = *logEntryIter;
159*75dac00eSOliver Brewka // Get the Message from the MessageRegistry
160*75dac00eSOliver Brewka const registries::Message* message = registries::getMessage(messageID);
161*75dac00eSOliver Brewka
162*75dac00eSOliver Brewka logEntryIter++;
163*75dac00eSOliver Brewka if (message == nullptr)
164*75dac00eSOliver Brewka {
165*75dac00eSOliver Brewka BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
166*75dac00eSOliver Brewka return LogParseError::messageIdNotInRegistry;
167*75dac00eSOliver Brewka }
168*75dac00eSOliver Brewka
169*75dac00eSOliver Brewka std::vector<std::string_view> messageArgs(logEntryIter,
170*75dac00eSOliver Brewka logEntryFields.end());
171*75dac00eSOliver Brewka messageArgs.resize(message->numberOfArgs);
172*75dac00eSOliver Brewka
173*75dac00eSOliver Brewka std::string msg =
174*75dac00eSOliver Brewka redfish::registries::fillMessageArgs(messageArgs, message->message);
175*75dac00eSOliver Brewka if (msg.empty())
176*75dac00eSOliver Brewka {
177*75dac00eSOliver Brewka return LogParseError::parseFailed;
178*75dac00eSOliver Brewka }
179*75dac00eSOliver Brewka
180*75dac00eSOliver Brewka // Get the Created time from the timestamp. The log timestamp is in RFC3339
181*75dac00eSOliver Brewka // format which matches the Redfish format except for the fractional seconds
182*75dac00eSOliver Brewka // between the '.' and the '+', so just remove them.
183*75dac00eSOliver Brewka std::size_t dot = timestamp.find_first_of('.');
184*75dac00eSOliver Brewka std::size_t plus = timestamp.find_first_of('+');
185*75dac00eSOliver Brewka if (dot != std::string::npos && plus != std::string::npos)
186*75dac00eSOliver Brewka {
187*75dac00eSOliver Brewka timestamp.erase(dot, plus - dot);
188*75dac00eSOliver Brewka }
189*75dac00eSOliver Brewka
190*75dac00eSOliver Brewka // Fill in the log entry with the gathered data
191*75dac00eSOliver Brewka logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
192*75dac00eSOliver Brewka logEntryJson["@odata.id"] = boost::urls::format(
193*75dac00eSOliver Brewka "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
194*75dac00eSOliver Brewka BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
195*75dac00eSOliver Brewka logEntryJson["Name"] = "System Event Log Entry";
196*75dac00eSOliver Brewka logEntryJson["Id"] = logEntryID;
197*75dac00eSOliver Brewka logEntryJson["Message"] = std::move(msg);
198*75dac00eSOliver Brewka logEntryJson["MessageId"] = std::move(messageID);
199*75dac00eSOliver Brewka logEntryJson["MessageArgs"] = messageArgs;
200*75dac00eSOliver Brewka logEntryJson["EntryType"] = "Event";
201*75dac00eSOliver Brewka logEntryJson["Severity"] = message->messageSeverity;
202*75dac00eSOliver Brewka logEntryJson["Created"] = std::move(timestamp);
203*75dac00eSOliver Brewka return LogParseError::success;
204*75dac00eSOliver Brewka }
205*75dac00eSOliver Brewka
handleSystemsLogServiceEventLogLogEntryCollection(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)206*75dac00eSOliver Brewka inline void handleSystemsLogServiceEventLogLogEntryCollection(
207*75dac00eSOliver Brewka App& app, const crow::Request& req,
208*75dac00eSOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
209*75dac00eSOliver Brewka const std::string& systemName)
210*75dac00eSOliver Brewka {
211*75dac00eSOliver Brewka query_param::QueryCapabilities capabilities = {
212*75dac00eSOliver Brewka .canDelegateTop = true,
213*75dac00eSOliver Brewka .canDelegateSkip = true,
214*75dac00eSOliver Brewka };
215*75dac00eSOliver Brewka query_param::Query delegatedQuery;
216*75dac00eSOliver Brewka if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
217*75dac00eSOliver Brewka delegatedQuery, capabilities))
218*75dac00eSOliver Brewka {
219*75dac00eSOliver Brewka return;
220*75dac00eSOliver Brewka }
221*75dac00eSOliver Brewka if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
222*75dac00eSOliver Brewka {
223*75dac00eSOliver Brewka // Option currently returns no systems. TBD
224*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem",
225*75dac00eSOliver Brewka systemName);
226*75dac00eSOliver Brewka return;
227*75dac00eSOliver Brewka }
228*75dac00eSOliver Brewka if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
229*75dac00eSOliver Brewka {
230*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem",
231*75dac00eSOliver Brewka systemName);
232*75dac00eSOliver Brewka return;
233*75dac00eSOliver Brewka }
234*75dac00eSOliver Brewka
235*75dac00eSOliver Brewka size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
236*75dac00eSOliver Brewka size_t skip = delegatedQuery.skip.value_or(0);
237*75dac00eSOliver Brewka
238*75dac00eSOliver Brewka // Collections don't include the static data added by SubRoute
239*75dac00eSOliver Brewka // because it has a duplicate entry for members
240*75dac00eSOliver Brewka asyncResp->res.jsonValue["@odata.type"] =
241*75dac00eSOliver Brewka "#LogEntryCollection.LogEntryCollection";
242*75dac00eSOliver Brewka asyncResp->res.jsonValue["@odata.id"] =
243*75dac00eSOliver Brewka std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
244*75dac00eSOliver Brewka BMCWEB_REDFISH_SYSTEM_URI_NAME);
245*75dac00eSOliver Brewka asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
246*75dac00eSOliver Brewka asyncResp->res.jsonValue["Description"] =
247*75dac00eSOliver Brewka "Collection of System Event Log Entries";
248*75dac00eSOliver Brewka
249*75dac00eSOliver Brewka nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
250*75dac00eSOliver Brewka logEntryArray = nlohmann::json::array();
251*75dac00eSOliver Brewka // Go through the log files and create a unique ID for each
252*75dac00eSOliver Brewka // entry
253*75dac00eSOliver Brewka std::vector<std::filesystem::path> redfishLogFiles;
254*75dac00eSOliver Brewka getRedfishLogFiles(redfishLogFiles);
255*75dac00eSOliver Brewka uint64_t entryCount = 0;
256*75dac00eSOliver Brewka std::string logEntry;
257*75dac00eSOliver Brewka
258*75dac00eSOliver Brewka // Oldest logs are in the last file, so start there and loop
259*75dac00eSOliver Brewka // backwards
260*75dac00eSOliver Brewka for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++)
261*75dac00eSOliver Brewka {
262*75dac00eSOliver Brewka std::ifstream logStream(*it);
263*75dac00eSOliver Brewka if (!logStream.is_open())
264*75dac00eSOliver Brewka {
265*75dac00eSOliver Brewka continue;
266*75dac00eSOliver Brewka }
267*75dac00eSOliver Brewka
268*75dac00eSOliver Brewka // Reset the unique ID on the first entry
269*75dac00eSOliver Brewka bool firstEntry = true;
270*75dac00eSOliver Brewka while (std::getline(logStream, logEntry))
271*75dac00eSOliver Brewka {
272*75dac00eSOliver Brewka std::string idStr;
273*75dac00eSOliver Brewka if (!getUniqueEntryID(logEntry, idStr, firstEntry))
274*75dac00eSOliver Brewka {
275*75dac00eSOliver Brewka continue;
276*75dac00eSOliver Brewka }
277*75dac00eSOliver Brewka firstEntry = false;
278*75dac00eSOliver Brewka
279*75dac00eSOliver Brewka nlohmann::json::object_t bmcLogEntry;
280*75dac00eSOliver Brewka LogParseError status =
281*75dac00eSOliver Brewka fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
282*75dac00eSOliver Brewka if (status == LogParseError::messageIdNotInRegistry)
283*75dac00eSOliver Brewka {
284*75dac00eSOliver Brewka continue;
285*75dac00eSOliver Brewka }
286*75dac00eSOliver Brewka if (status != LogParseError::success)
287*75dac00eSOliver Brewka {
288*75dac00eSOliver Brewka messages::internalError(asyncResp->res);
289*75dac00eSOliver Brewka return;
290*75dac00eSOliver Brewka }
291*75dac00eSOliver Brewka
292*75dac00eSOliver Brewka entryCount++;
293*75dac00eSOliver Brewka // Handle paging using skip (number of entries to skip from the
294*75dac00eSOliver Brewka // start) and top (number of entries to display)
295*75dac00eSOliver Brewka if (entryCount <= skip || entryCount > skip + top)
296*75dac00eSOliver Brewka {
297*75dac00eSOliver Brewka continue;
298*75dac00eSOliver Brewka }
299*75dac00eSOliver Brewka
300*75dac00eSOliver Brewka logEntryArray.emplace_back(std::move(bmcLogEntry));
301*75dac00eSOliver Brewka }
302*75dac00eSOliver Brewka }
303*75dac00eSOliver Brewka asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
304*75dac00eSOliver Brewka if (skip + top < entryCount)
305*75dac00eSOliver Brewka {
306*75dac00eSOliver Brewka asyncResp->res.jsonValue["Members@odata.nextLink"] =
307*75dac00eSOliver Brewka boost::urls::format(
308*75dac00eSOliver Brewka "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}",
309*75dac00eSOliver Brewka BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top));
310*75dac00eSOliver Brewka }
311*75dac00eSOliver Brewka }
312*75dac00eSOliver Brewka
handleSystemsLogServiceEventLogEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & param)313*75dac00eSOliver Brewka inline void handleSystemsLogServiceEventLogEntriesGet(
314*75dac00eSOliver Brewka App& app, const crow::Request& req,
315*75dac00eSOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
316*75dac00eSOliver Brewka const std::string& systemName, const std::string& param)
317*75dac00eSOliver Brewka {
318*75dac00eSOliver Brewka if (!redfish::setUpRedfishRoute(app, req, asyncResp))
319*75dac00eSOliver Brewka {
320*75dac00eSOliver Brewka return;
321*75dac00eSOliver Brewka }
322*75dac00eSOliver Brewka if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
323*75dac00eSOliver Brewka {
324*75dac00eSOliver Brewka // Option currently returns no systems. TBD
325*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem",
326*75dac00eSOliver Brewka systemName);
327*75dac00eSOliver Brewka return;
328*75dac00eSOliver Brewka }
329*75dac00eSOliver Brewka
330*75dac00eSOliver Brewka if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
331*75dac00eSOliver Brewka {
332*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem",
333*75dac00eSOliver Brewka systemName);
334*75dac00eSOliver Brewka return;
335*75dac00eSOliver Brewka }
336*75dac00eSOliver Brewka
337*75dac00eSOliver Brewka const std::string& targetID = param;
338*75dac00eSOliver Brewka
339*75dac00eSOliver Brewka // Go through the log files and check the unique ID for each
340*75dac00eSOliver Brewka // entry to find the target entry
341*75dac00eSOliver Brewka std::vector<std::filesystem::path> redfishLogFiles;
342*75dac00eSOliver Brewka getRedfishLogFiles(redfishLogFiles);
343*75dac00eSOliver Brewka std::string logEntry;
344*75dac00eSOliver Brewka
345*75dac00eSOliver Brewka // Oldest logs are in the last file, so start there and loop
346*75dac00eSOliver Brewka // backwards
347*75dac00eSOliver Brewka for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++)
348*75dac00eSOliver Brewka {
349*75dac00eSOliver Brewka std::ifstream logStream(*it);
350*75dac00eSOliver Brewka if (!logStream.is_open())
351*75dac00eSOliver Brewka {
352*75dac00eSOliver Brewka continue;
353*75dac00eSOliver Brewka }
354*75dac00eSOliver Brewka
355*75dac00eSOliver Brewka // Reset the unique ID on the first entry
356*75dac00eSOliver Brewka bool firstEntry = true;
357*75dac00eSOliver Brewka while (std::getline(logStream, logEntry))
358*75dac00eSOliver Brewka {
359*75dac00eSOliver Brewka std::string idStr;
360*75dac00eSOliver Brewka if (!getUniqueEntryID(logEntry, idStr, firstEntry))
361*75dac00eSOliver Brewka {
362*75dac00eSOliver Brewka continue;
363*75dac00eSOliver Brewka }
364*75dac00eSOliver Brewka firstEntry = false;
365*75dac00eSOliver Brewka
366*75dac00eSOliver Brewka if (idStr == targetID)
367*75dac00eSOliver Brewka {
368*75dac00eSOliver Brewka nlohmann::json::object_t bmcLogEntry;
369*75dac00eSOliver Brewka LogParseError status =
370*75dac00eSOliver Brewka fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
371*75dac00eSOliver Brewka if (status != LogParseError::success)
372*75dac00eSOliver Brewka {
373*75dac00eSOliver Brewka messages::internalError(asyncResp->res);
374*75dac00eSOliver Brewka return;
375*75dac00eSOliver Brewka }
376*75dac00eSOliver Brewka asyncResp->res.jsonValue.update(bmcLogEntry);
377*75dac00eSOliver Brewka return;
378*75dac00eSOliver Brewka }
379*75dac00eSOliver Brewka }
380*75dac00eSOliver Brewka }
381*75dac00eSOliver Brewka // Requested ID was not found
382*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
383*75dac00eSOliver Brewka }
384*75dac00eSOliver Brewka
handleSystemsLogServicesEventLogActionsClearPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)385*75dac00eSOliver Brewka inline void handleSystemsLogServicesEventLogActionsClearPost(
386*75dac00eSOliver Brewka App& app, const crow::Request& req,
387*75dac00eSOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
388*75dac00eSOliver Brewka const std::string& systemName)
389*75dac00eSOliver Brewka {
390*75dac00eSOliver Brewka if (!redfish::setUpRedfishRoute(app, req, asyncResp))
391*75dac00eSOliver Brewka {
392*75dac00eSOliver Brewka return;
393*75dac00eSOliver Brewka }
394*75dac00eSOliver Brewka if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
395*75dac00eSOliver Brewka {
396*75dac00eSOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem",
397*75dac00eSOliver Brewka systemName);
398*75dac00eSOliver Brewka return;
399*75dac00eSOliver Brewka }
400*75dac00eSOliver Brewka
401*75dac00eSOliver Brewka // Clear the EventLog by deleting the log files
402*75dac00eSOliver Brewka std::vector<std::filesystem::path> redfishLogFiles;
403*75dac00eSOliver Brewka if (getRedfishLogFiles(redfishLogFiles))
404*75dac00eSOliver Brewka {
405*75dac00eSOliver Brewka for (const std::filesystem::path& file : redfishLogFiles)
406*75dac00eSOliver Brewka {
407*75dac00eSOliver Brewka std::error_code ec;
408*75dac00eSOliver Brewka std::filesystem::remove(file, ec);
409*75dac00eSOliver Brewka }
410*75dac00eSOliver Brewka }
411*75dac00eSOliver Brewka
412*75dac00eSOliver Brewka // Reload rsyslog so it knows to start new log files
413*75dac00eSOliver Brewka dbus::utility::async_method_call(
414*75dac00eSOliver Brewka asyncResp,
415*75dac00eSOliver Brewka [asyncResp](const boost::system::error_code& ec) {
416*75dac00eSOliver Brewka if (ec)
417*75dac00eSOliver Brewka {
418*75dac00eSOliver Brewka BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
419*75dac00eSOliver Brewka messages::internalError(asyncResp->res);
420*75dac00eSOliver Brewka return;
421*75dac00eSOliver Brewka }
422*75dac00eSOliver Brewka
423*75dac00eSOliver Brewka messages::success(asyncResp->res);
424*75dac00eSOliver Brewka },
425*75dac00eSOliver Brewka "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
426*75dac00eSOliver Brewka "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
427*75dac00eSOliver Brewka "replace");
428*75dac00eSOliver Brewka }
429*75dac00eSOliver Brewka
requestRoutesJournalEventLogEntryCollection(App & app)430*75dac00eSOliver Brewka inline void requestRoutesJournalEventLogEntryCollection(App& app)
431*75dac00eSOliver Brewka {
432*75dac00eSOliver Brewka BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
433*75dac00eSOliver Brewka .privileges(redfish::privileges::getLogEntryCollection)
434*75dac00eSOliver Brewka .methods(boost::beast::http::verb::get)(std::bind_front(
435*75dac00eSOliver Brewka handleSystemsLogServiceEventLogLogEntryCollection, std::ref(app)));
436*75dac00eSOliver Brewka }
437*75dac00eSOliver Brewka
requestRoutesJournalEventLogEntry(App & app)438*75dac00eSOliver Brewka inline void requestRoutesJournalEventLogEntry(App& app)
439*75dac00eSOliver Brewka {
440*75dac00eSOliver Brewka BMCWEB_ROUTE(
441*75dac00eSOliver Brewka app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
442*75dac00eSOliver Brewka .privileges(redfish::privileges::getLogEntry)
443*75dac00eSOliver Brewka .methods(boost::beast::http::verb::get)(std::bind_front(
444*75dac00eSOliver Brewka handleSystemsLogServiceEventLogEntriesGet, std::ref(app)));
445*75dac00eSOliver Brewka }
446*75dac00eSOliver Brewka
requestRoutesJournalEventLogClear(App & app)447*75dac00eSOliver Brewka inline void requestRoutesJournalEventLogClear(App& app)
448*75dac00eSOliver Brewka {
449*75dac00eSOliver Brewka BMCWEB_ROUTE(
450*75dac00eSOliver Brewka app,
451*75dac00eSOliver Brewka "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
452*75dac00eSOliver Brewka .privileges(redfish::privileges::
453*75dac00eSOliver Brewka postLogServiceSubOverComputerSystemLogServiceCollection)
454*75dac00eSOliver Brewka .methods(boost::beast::http::verb::post)(std::bind_front(
455*75dac00eSOliver Brewka handleSystemsLogServicesEventLogActionsClearPost, std::ref(app)));
456*75dac00eSOliver Brewka }
457*75dac00eSOliver Brewka } // namespace redfish
458