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 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 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 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 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 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 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 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 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 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