11da66f75SEd Tanous /* 21da66f75SEd Tanous // Copyright (c) 2018 Intel Corporation 31da66f75SEd Tanous // 41da66f75SEd Tanous // Licensed under the Apache License, Version 2.0 (the "License"); 51da66f75SEd Tanous // you may not use this file except in compliance with the License. 61da66f75SEd Tanous // You may obtain a copy of the License at 71da66f75SEd Tanous // 81da66f75SEd Tanous // http://www.apache.org/licenses/LICENSE-2.0 91da66f75SEd Tanous // 101da66f75SEd Tanous // Unless required by applicable law or agreed to in writing, software 111da66f75SEd Tanous // distributed under the License is distributed on an "AS IS" BASIS, 121da66f75SEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131da66f75SEd Tanous // See the License for the specific language governing permissions and 141da66f75SEd Tanous // limitations under the License. 151da66f75SEd Tanous */ 161da66f75SEd Tanous #pragma once 171da66f75SEd Tanous 183ccb3adbSEd Tanous #include "app.hpp" 197a1dbc48SGeorge Liu #include "dbus_utility.hpp" 203ccb3adbSEd Tanous #include "error_messages.hpp" 2168dd075aSAsmitha Karunanithi #include "generated/enums/log_entry.hpp" 22b7028ebfSSpencer Ku #include "gzfile.hpp" 23647b3cdcSGeorge Liu #include "http_utility.hpp" 24b7028ebfSSpencer Ku #include "human_sort.hpp" 253ccb3adbSEd Tanous #include "query.hpp" 264851d45dSJason M. Bills #include "registries.hpp" 274851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 284851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 293ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 3046229577SJames Feist #include "task.hpp" 315b90429aSEd Tanous #include "task_messages.hpp" 323ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 335b90429aSEd Tanous #include "utils/json_utils.hpp" 343ccb3adbSEd Tanous #include "utils/time_utils.hpp" 351da66f75SEd Tanous 3675e8e218SMyung Bae #include <systemd/sd-id128.h> 378e31778eSAsmitha Karunanithi #include <tinyxml2.h> 38400fd1fbSAdriana Kobylak #include <unistd.h> 39e1f26343SJason M. Bills 4007c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 411da66f75SEd Tanous #include <boost/container/flat_map.hpp> 421ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 43ef4c65b7SEd Tanous #include <boost/url/format.hpp> 44d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 45d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 461214b7e7SGunnar Mills 477a1dbc48SGeorge Liu #include <array> 48647b3cdcSGeorge Liu #include <charconv> 49b5f288d2SAbhilash Raju #include <cstddef> 504418c7f0SJames Feist #include <filesystem> 5118f8f608SEd Tanous #include <iterator> 5275710de2SXiaochao Ma #include <optional> 533544d2a7SEd Tanous #include <ranges> 5426702d01SEd Tanous #include <span> 5518f8f608SEd Tanous #include <string> 56cd225da8SJason M. Bills #include <string_view> 57abf2add6SEd Tanous #include <variant> 581da66f75SEd Tanous 591da66f75SEd Tanous namespace redfish 601da66f75SEd Tanous { 611da66f75SEd Tanous 6289492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6389492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6489492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6589492a15SPatrick Williams constexpr const char* deleteAllInterface = 665b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6789492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 68424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6989492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 706eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 711da66f75SEd Tanous 728e31778eSAsmitha Karunanithi enum class DumpCreationProgress 738e31778eSAsmitha Karunanithi { 748e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 758e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 768e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 778e31778eSAsmitha Karunanithi }; 788e31778eSAsmitha Karunanithi 79f6150403SJames Feist namespace fs = std::filesystem; 801da66f75SEd Tanous 81cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 82cb92c03bSAndrew Geissler { 83d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 86d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 87cb92c03bSAndrew Geissler { 88cb92c03bSAndrew Geissler return "Critical"; 89cb92c03bSAndrew Geissler } 903174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 91d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 92d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 93cb92c03bSAndrew Geissler { 94cb92c03bSAndrew Geissler return "OK"; 95cb92c03bSAndrew Geissler } 963174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 97cb92c03bSAndrew Geissler { 98cb92c03bSAndrew Geissler return "Warning"; 99cb92c03bSAndrew Geissler } 100cb92c03bSAndrew Geissler return ""; 101cb92c03bSAndrew Geissler } 102cb92c03bSAndrew Geissler 1039017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1049017faf2SAbhishek Patel { 1059017faf2SAbhishek Patel std::optional<bool> notifyAction; 1069017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1079017faf2SAbhishek Patel { 1089017faf2SAbhishek Patel notifyAction = true; 1099017faf2SAbhishek Patel } 1109017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1119017faf2SAbhishek Patel { 1129017faf2SAbhishek Patel notifyAction = false; 1139017faf2SAbhishek Patel } 1149017faf2SAbhishek Patel 1159017faf2SAbhishek Patel return notifyAction; 1169017faf2SAbhishek Patel } 1179017faf2SAbhishek Patel 11818f8f608SEd Tanous inline std::string getDumpPath(std::string_view dumpType) 11918f8f608SEd Tanous { 12018f8f608SEd Tanous std::string dbusDumpPath = "/xyz/openbmc_project/dump/"; 12118f8f608SEd Tanous std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath), 12218f8f608SEd Tanous bmcweb::asciiToLower); 12318f8f608SEd Tanous 12418f8f608SEd Tanous return dbusDumpPath; 12518f8f608SEd Tanous } 12618f8f608SEd Tanous 127*055713e4SEd Tanous inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 128e85d6b16SJason M. Bills const bool firstEntry = true) 12995820184SJason M. Bills { 130271584abSEd Tanous static time_t prevTs = 0; 13195820184SJason M. Bills static int index = 0; 132e85d6b16SJason M. Bills if (firstEntry) 133e85d6b16SJason M. Bills { 134e85d6b16SJason M. Bills prevTs = 0; 135e85d6b16SJason M. Bills } 136e85d6b16SJason M. Bills 13795820184SJason M. Bills // Get the entry timestamp 138271584abSEd Tanous std::time_t curTs = 0; 13995820184SJason M. Bills std::tm timeStruct = {}; 14095820184SJason M. Bills std::istringstream entryStream(logEntry); 14195820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 14295820184SJason M. Bills { 14395820184SJason M. Bills curTs = std::mktime(&timeStruct); 14495820184SJason M. Bills } 14595820184SJason M. Bills // If the timestamp isn't unique, increment the index 14695820184SJason M. Bills if (curTs == prevTs) 14795820184SJason M. Bills { 14895820184SJason M. Bills index++; 14995820184SJason M. Bills } 15095820184SJason M. Bills else 15195820184SJason M. Bills { 15295820184SJason M. Bills // Otherwise, reset it 15395820184SJason M. Bills index = 0; 15495820184SJason M. Bills } 15595820184SJason M. Bills // Save the timestamp 15695820184SJason M. Bills prevTs = curTs; 15795820184SJason M. Bills 15895820184SJason M. Bills entryID = std::to_string(curTs); 15995820184SJason M. Bills if (index > 0) 16095820184SJason M. Bills { 16195820184SJason M. Bills entryID += "_" + std::to_string(index); 16295820184SJason M. Bills } 16395820184SJason M. Bills return true; 16495820184SJason M. Bills } 16595820184SJason M. Bills 16695820184SJason M. Bills static bool 16795820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 16895820184SJason M. Bills { 16995820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 17095820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 17195820184SJason M. Bills 17295820184SJason M. Bills // Loop through the directory looking for redfish log files 17395820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 17495820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 17595820184SJason M. Bills { 17695820184SJason M. Bills // If we find a redfish log file, save the path 17795820184SJason M. Bills std::string filename = dirEnt.path().filename(); 17811ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 17995820184SJason M. Bills { 18095820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 18195820184SJason M. Bills } 18295820184SJason M. Bills } 18395820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 18495820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 18595820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 1863544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 18795820184SJason M. Bills 18895820184SJason M. Bills return !redfishLogFiles.empty(); 18995820184SJason M. Bills } 19095820184SJason M. Bills 19168dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 19268dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 19368dd075aSAsmitha Karunanithi { 19468dd075aSAsmitha Karunanithi if (originatorType == 19568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 19668dd075aSAsmitha Karunanithi { 19768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 19868dd075aSAsmitha Karunanithi } 19968dd075aSAsmitha Karunanithi if (originatorType == 20068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 20168dd075aSAsmitha Karunanithi { 20268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 20368dd075aSAsmitha Karunanithi } 20468dd075aSAsmitha Karunanithi if (originatorType == 20568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 20668dd075aSAsmitha Karunanithi { 20768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 20868dd075aSAsmitha Karunanithi } 20968dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 21068dd075aSAsmitha Karunanithi } 21168dd075aSAsmitha Karunanithi 212aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 2132d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 214c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 21568dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 216aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 217aefe3786SClaire Weinan { 218aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 219aefe3786SClaire Weinan { 220aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 221aefe3786SClaire Weinan { 222aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 223aefe3786SClaire Weinan { 224aefe3786SClaire Weinan if (propertyMap.first == "Status") 225aefe3786SClaire Weinan { 226aefe3786SClaire Weinan const auto* status = 227aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 228aefe3786SClaire Weinan if (status == nullptr) 229aefe3786SClaire Weinan { 230aefe3786SClaire Weinan messages::internalError(asyncResp->res); 231aefe3786SClaire Weinan break; 232aefe3786SClaire Weinan } 233aefe3786SClaire Weinan dumpStatus = *status; 234aefe3786SClaire Weinan } 235aefe3786SClaire Weinan } 236aefe3786SClaire Weinan } 237aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 238aefe3786SClaire Weinan { 239aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 240aefe3786SClaire Weinan { 241aefe3786SClaire Weinan if (propertyMap.first == "Size") 242aefe3786SClaire Weinan { 243aefe3786SClaire Weinan const auto* sizePtr = 244aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 245aefe3786SClaire Weinan if (sizePtr == nullptr) 246aefe3786SClaire Weinan { 247aefe3786SClaire Weinan messages::internalError(asyncResp->res); 248aefe3786SClaire Weinan break; 249aefe3786SClaire Weinan } 250aefe3786SClaire Weinan size = *sizePtr; 251aefe3786SClaire Weinan break; 252aefe3786SClaire Weinan } 253aefe3786SClaire Weinan } 254aefe3786SClaire Weinan } 255aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 256aefe3786SClaire Weinan { 257aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 258aefe3786SClaire Weinan { 259aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 260aefe3786SClaire Weinan { 261aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 262aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 263aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 264aefe3786SClaire Weinan { 265aefe3786SClaire Weinan messages::internalError(asyncResp->res); 266aefe3786SClaire Weinan break; 267aefe3786SClaire Weinan } 268c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 269aefe3786SClaire Weinan break; 270aefe3786SClaire Weinan } 271aefe3786SClaire Weinan } 272aefe3786SClaire Weinan } 27368dd075aSAsmitha Karunanithi else if (interfaceMap.first == 27468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 27568dd075aSAsmitha Karunanithi { 27668dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 27768dd075aSAsmitha Karunanithi { 27868dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 27968dd075aSAsmitha Karunanithi { 28068dd075aSAsmitha Karunanithi const std::string* id = 28168dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 28268dd075aSAsmitha Karunanithi if (id == nullptr) 28368dd075aSAsmitha Karunanithi { 28468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 28568dd075aSAsmitha Karunanithi break; 28668dd075aSAsmitha Karunanithi } 28768dd075aSAsmitha Karunanithi originatorId = *id; 28868dd075aSAsmitha Karunanithi } 28968dd075aSAsmitha Karunanithi 29068dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 29168dd075aSAsmitha Karunanithi { 29268dd075aSAsmitha Karunanithi const std::string* type = 29368dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 29468dd075aSAsmitha Karunanithi if (type == nullptr) 29568dd075aSAsmitha Karunanithi { 29668dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 29768dd075aSAsmitha Karunanithi break; 29868dd075aSAsmitha Karunanithi } 29968dd075aSAsmitha Karunanithi 30068dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 30168dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 30268dd075aSAsmitha Karunanithi { 30368dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 30468dd075aSAsmitha Karunanithi break; 30568dd075aSAsmitha Karunanithi } 30668dd075aSAsmitha Karunanithi } 30768dd075aSAsmitha Karunanithi } 30868dd075aSAsmitha Karunanithi } 309aefe3786SClaire Weinan } 310aefe3786SClaire Weinan } 311aefe3786SClaire Weinan 31221ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 313fdd26906SClaire Weinan { 314fdd26906SClaire Weinan std::string entriesPath; 315fdd26906SClaire Weinan 316fdd26906SClaire Weinan if (dumpType == "BMC") 317fdd26906SClaire Weinan { 318253f11b8SEd Tanous entriesPath = 319253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 320253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 321fdd26906SClaire Weinan } 322fdd26906SClaire Weinan else if (dumpType == "FaultLog") 323fdd26906SClaire Weinan { 324253f11b8SEd Tanous entriesPath = 325253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/FaultLog/Entries/", 326253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 327fdd26906SClaire Weinan } 328fdd26906SClaire Weinan else if (dumpType == "System") 329fdd26906SClaire Weinan { 330253f11b8SEd Tanous entriesPath = 331253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 332253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 333fdd26906SClaire Weinan } 334fdd26906SClaire Weinan else 335fdd26906SClaire Weinan { 33662598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 33762598e31SEd Tanous dumpType); 338fdd26906SClaire Weinan } 339fdd26906SClaire Weinan 340fdd26906SClaire Weinan // Returns empty string on error 341fdd26906SClaire Weinan return entriesPath; 342fdd26906SClaire Weinan } 343fdd26906SClaire Weinan 3448d1b46d7Szhanghch05 inline void 3458d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3465cb1dd27SAsmitha Karunanithi const std::string& dumpType) 3475cb1dd27SAsmitha Karunanithi { 348fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 349fdd26906SClaire Weinan if (entriesPath.empty()) 3505cb1dd27SAsmitha Karunanithi { 3515cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 3525cb1dd27SAsmitha Karunanithi return; 3535cb1dd27SAsmitha Karunanithi } 3545cb1dd27SAsmitha Karunanithi 3555eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 3565eb468daSGeorge Liu dbus::utility::getManagedObjects( 3575eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 358fdd26906SClaire Weinan [asyncResp, entriesPath, 3595e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 3605eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 3615cb1dd27SAsmitha Karunanithi if (ec) 3625cb1dd27SAsmitha Karunanithi { 36362598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 3645cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 3655cb1dd27SAsmitha Karunanithi return; 3665cb1dd27SAsmitha Karunanithi } 3675cb1dd27SAsmitha Karunanithi 368fdd26906SClaire Weinan // Remove ending slash 369fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 370fdd26906SClaire Weinan if (!odataIdStr.empty()) 371fdd26906SClaire Weinan { 372fdd26906SClaire Weinan odataIdStr.pop_back(); 373fdd26906SClaire Weinan } 374fdd26906SClaire Weinan 375fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 376fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 377fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 378fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 37989492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 38089492a15SPatrick Williams " Dump Entries"; 381fdd26906SClaire Weinan 3823544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 38318f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 3845cb1dd27SAsmitha Karunanithi 3855eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 3863544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 387002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 388002d39b4SEd Tanous r.first.filename()); 389565dfb6fSClaire Weinan }); 390565dfb6fSClaire Weinan 3915cb1dd27SAsmitha Karunanithi for (auto& object : resp) 3925cb1dd27SAsmitha Karunanithi { 393b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 3945cb1dd27SAsmitha Karunanithi { 3955cb1dd27SAsmitha Karunanithi continue; 3965cb1dd27SAsmitha Karunanithi } 397c6fecdabSClaire Weinan uint64_t timestampUs = 0; 3985cb1dd27SAsmitha Karunanithi uint64_t size = 0; 39935440d18SAsmitha Karunanithi std::string dumpStatus; 40068dd075aSAsmitha Karunanithi std::string originatorId; 40168dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 40268dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 403433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 4042dfd18efSEd Tanous 4052dfd18efSEd Tanous std::string entryID = object.first.filename(); 4062dfd18efSEd Tanous if (entryID.empty()) 4075cb1dd27SAsmitha Karunanithi { 4085cb1dd27SAsmitha Karunanithi continue; 4095cb1dd27SAsmitha Karunanithi } 4105cb1dd27SAsmitha Karunanithi 411c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 41268dd075aSAsmitha Karunanithi originatorId, originatorType, 413aefe3786SClaire Weinan asyncResp); 4145cb1dd27SAsmitha Karunanithi 4150fda0f12SGeorge Liu if (dumpStatus != 4160fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 41735440d18SAsmitha Karunanithi !dumpStatus.empty()) 41835440d18SAsmitha Karunanithi { 41935440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 42035440d18SAsmitha Karunanithi continue; 42135440d18SAsmitha Karunanithi } 42235440d18SAsmitha Karunanithi 42368dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 424fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 4255cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 4265cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 4275cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 428bbd80db8SClaire Weinan thisEntry["Created"] = 429bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 4305cb1dd27SAsmitha Karunanithi 43168dd075aSAsmitha Karunanithi if (!originatorId.empty()) 43268dd075aSAsmitha Karunanithi { 43368dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 43468dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 43568dd075aSAsmitha Karunanithi } 43668dd075aSAsmitha Karunanithi 4375cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 4385cb1dd27SAsmitha Karunanithi { 439d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 44089492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 44189492a15SPatrick Williams "/attachment"; 442fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 4435cb1dd27SAsmitha Karunanithi } 4445cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 4455cb1dd27SAsmitha Karunanithi { 446d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 447d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 44889492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 44989492a15SPatrick Williams "/attachment"; 450fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 4515cb1dd27SAsmitha Karunanithi } 452b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 4535cb1dd27SAsmitha Karunanithi } 454002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 4553544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 4565eb468daSGeorge Liu }); 4575cb1dd27SAsmitha Karunanithi } 4585cb1dd27SAsmitha Karunanithi 4598d1b46d7Szhanghch05 inline void 460c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4618d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 4625cb1dd27SAsmitha Karunanithi { 463fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 464fdd26906SClaire Weinan if (entriesPath.empty()) 4655cb1dd27SAsmitha Karunanithi { 4665cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4675cb1dd27SAsmitha Karunanithi return; 4685cb1dd27SAsmitha Karunanithi } 4695cb1dd27SAsmitha Karunanithi 4705eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4715eb468daSGeorge Liu dbus::utility::getManagedObjects( 4725eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 473fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 4745e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 47502cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 4765cb1dd27SAsmitha Karunanithi if (ec) 4775cb1dd27SAsmitha Karunanithi { 47862598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 4795cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4805cb1dd27SAsmitha Karunanithi return; 4815cb1dd27SAsmitha Karunanithi } 4825cb1dd27SAsmitha Karunanithi 483b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 48418f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 485b47452b2SAsmitha Karunanithi 4869eb808c1SEd Tanous for (const auto& objectPath : resp) 4875cb1dd27SAsmitha Karunanithi { 488b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 4895cb1dd27SAsmitha Karunanithi { 4905cb1dd27SAsmitha Karunanithi continue; 4915cb1dd27SAsmitha Karunanithi } 4925cb1dd27SAsmitha Karunanithi 4935cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 494c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4955cb1dd27SAsmitha Karunanithi uint64_t size = 0; 49635440d18SAsmitha Karunanithi std::string dumpStatus; 49768dd075aSAsmitha Karunanithi std::string originatorId; 49868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 49968dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 5005cb1dd27SAsmitha Karunanithi 501aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 50268dd075aSAsmitha Karunanithi timestampUs, originatorId, 50368dd075aSAsmitha Karunanithi originatorType, asyncResp); 5045cb1dd27SAsmitha Karunanithi 5050fda0f12SGeorge Liu if (dumpStatus != 5060fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 50735440d18SAsmitha Karunanithi !dumpStatus.empty()) 50835440d18SAsmitha Karunanithi { 50935440d18SAsmitha Karunanithi // Dump status is not Complete 51035440d18SAsmitha Karunanithi // return not found until status is changed to Completed 511d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 512d1bde9e5SKrzysztof Grobelny entryID); 51335440d18SAsmitha Karunanithi return; 51435440d18SAsmitha Karunanithi } 51535440d18SAsmitha Karunanithi 5165cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 51768dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 518fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5195cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 5205cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 5215cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 522bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 523bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5245cb1dd27SAsmitha Karunanithi 52568dd075aSAsmitha Karunanithi if (!originatorId.empty()) 52668dd075aSAsmitha Karunanithi { 52768dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 52868dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 52968dd075aSAsmitha Karunanithi } 53068dd075aSAsmitha Karunanithi 5315cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5325cb1dd27SAsmitha Karunanithi { 533d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 534d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 535fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 536fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5375cb1dd27SAsmitha Karunanithi } 5385cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5395cb1dd27SAsmitha Karunanithi { 540d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 541002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 542d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 543fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 544fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5455cb1dd27SAsmitha Karunanithi } 5465cb1dd27SAsmitha Karunanithi } 547e05aec50SEd Tanous if (!foundDumpEntry) 548b47452b2SAsmitha Karunanithi { 54962598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 550b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 551b90d14f2SMyung Bae entryID); 552b47452b2SAsmitha Karunanithi return; 553b47452b2SAsmitha Karunanithi } 5545eb468daSGeorge Liu }); 5555cb1dd27SAsmitha Karunanithi } 5565cb1dd27SAsmitha Karunanithi 5578d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5589878256fSStanley Chu const std::string& entryID, 559b47452b2SAsmitha Karunanithi const std::string& dumpType) 5605cb1dd27SAsmitha Karunanithi { 5615a39f77aSPatrick Williams auto respHandler = [asyncResp, 5625a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 56362598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 5645cb1dd27SAsmitha Karunanithi if (ec) 5655cb1dd27SAsmitha Karunanithi { 5663de8d8baSGeorge Liu if (ec.value() == EBADR) 5673de8d8baSGeorge Liu { 5683de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 5693de8d8baSGeorge Liu return; 5703de8d8baSGeorge Liu } 57162598e31SEd Tanous BMCWEB_LOG_ERROR( 57262598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 57362598e31SEd Tanous entryID); 5745cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5755cb1dd27SAsmitha Karunanithi return; 5765cb1dd27SAsmitha Karunanithi } 5775cb1dd27SAsmitha Karunanithi }; 57818f8f608SEd Tanous 5795cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 5805cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 58118f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 5825cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 5835cb1dd27SAsmitha Karunanithi } 584b5f288d2SAbhilash Raju inline bool checkSizeLimit(int fd, crow::Response& res) 585b5f288d2SAbhilash Raju { 586b5f288d2SAbhilash Raju long long int size = lseek(fd, 0, SEEK_END); 587b5f288d2SAbhilash Raju if (size <= 0) 588b5f288d2SAbhilash Raju { 589b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 590b5f288d2SAbhilash Raju size); 591b5f288d2SAbhilash Raju messages::internalError(res); 592b5f288d2SAbhilash Raju return false; 593b5f288d2SAbhilash Raju } 5945cb1dd27SAsmitha Karunanithi 595b5f288d2SAbhilash Raju // Arbitrary max size of 20MB to accommodate BMC dumps 596b5f288d2SAbhilash Raju constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 597b5f288d2SAbhilash Raju if (size > maxFileSize) 598b5f288d2SAbhilash Raju { 599b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 600b5f288d2SAbhilash Raju size, maxFileSize); 601b5f288d2SAbhilash Raju messages::internalError(res); 602b5f288d2SAbhilash Raju return false; 603b5f288d2SAbhilash Raju } 604b5f288d2SAbhilash Raju off_t rc = lseek(fd, 0, SEEK_SET); 605b5f288d2SAbhilash Raju if (rc < 0) 606b5f288d2SAbhilash Raju { 607b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 608b5f288d2SAbhilash Raju messages::internalError(res); 609b5f288d2SAbhilash Raju return false; 610b5f288d2SAbhilash Raju } 611b5f288d2SAbhilash Raju return true; 612b5f288d2SAbhilash Raju } 613168d1b1aSCarson Labrado inline void 614168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 615168d1b1aSCarson Labrado const std::string& entryID, 616168d1b1aSCarson Labrado const std::string& downloadEntryType, 617168d1b1aSCarson Labrado const boost::system::error_code& ec, 618168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 619168d1b1aSCarson Labrado { 620168d1b1aSCarson Labrado if (ec.value() == EBADR) 621168d1b1aSCarson Labrado { 622168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 623168d1b1aSCarson Labrado return; 624168d1b1aSCarson Labrado } 625168d1b1aSCarson Labrado if (ec) 626168d1b1aSCarson Labrado { 627168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 628168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 629168d1b1aSCarson Labrado return; 630168d1b1aSCarson Labrado } 631168d1b1aSCarson Labrado 632168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 633168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 634168d1b1aSCarson Labrado { 635168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 636168d1b1aSCarson Labrado downloadEntryType); 637168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 638168d1b1aSCarson Labrado } 639168d1b1aSCarson Labrado 640168d1b1aSCarson Labrado int fd = -1; 641168d1b1aSCarson Labrado fd = dup(unixfd); 642168d1b1aSCarson Labrado if (fd < 0) 643168d1b1aSCarson Labrado { 644168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 645168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 646168d1b1aSCarson Labrado return; 647168d1b1aSCarson Labrado } 648b5f288d2SAbhilash Raju if (!checkSizeLimit(fd, asyncResp->res)) 649168d1b1aSCarson Labrado { 650168d1b1aSCarson Labrado close(fd); 651168d1b1aSCarson Labrado return; 652168d1b1aSCarson Labrado } 653168d1b1aSCarson Labrado if (downloadEntryType == "System") 654168d1b1aSCarson Labrado { 655b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 656b5f288d2SAbhilash Raju { 657b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 658b5f288d2SAbhilash Raju close(fd); 659b5f288d2SAbhilash Raju return; 660b5f288d2SAbhilash Raju } 661168d1b1aSCarson Labrado asyncResp->res.addHeader( 662168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 663b5f288d2SAbhilash Raju return; 664168d1b1aSCarson Labrado } 665b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd)) 66627b0cf90SEd Tanous { 667b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 668b5f288d2SAbhilash Raju close(fd); 669b5f288d2SAbhilash Raju return; 67027b0cf90SEd Tanous } 671168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 672168d1b1aSCarson Labrado "application/octet-stream"); 673168d1b1aSCarson Labrado } 674168d1b1aSCarson Labrado 675168d1b1aSCarson Labrado inline void 676168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 677168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 678168d1b1aSCarson Labrado { 679168d1b1aSCarson Labrado if (dumpType != "BMC") 680168d1b1aSCarson Labrado { 681168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 682168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 683168d1b1aSCarson Labrado return; 684168d1b1aSCarson Labrado } 685168d1b1aSCarson Labrado 68618f8f608SEd Tanous std::string dumpEntryPath = std::format("{}/entry/{}", 68718f8f608SEd Tanous getDumpPath(dumpType), entryID); 688168d1b1aSCarson Labrado 689168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 690168d1b1aSCarson Labrado [asyncResp, entryID, 691168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 692168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 693168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 694168d1b1aSCarson Labrado }; 695168d1b1aSCarson Labrado 696168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 697168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 698168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 699168d1b1aSCarson Labrado } 700168d1b1aSCarson Labrado 701168d1b1aSCarson Labrado inline void 702168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 703168d1b1aSCarson Labrado const std::string& systemName, 704168d1b1aSCarson Labrado const std::string& entryID, 705168d1b1aSCarson Labrado const std::string& dumpType) 706168d1b1aSCarson Labrado { 70725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 708168d1b1aSCarson Labrado { 709168d1b1aSCarson Labrado // Option currently returns no systems. TBD 710168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 711168d1b1aSCarson Labrado systemName); 712168d1b1aSCarson Labrado return; 713168d1b1aSCarson Labrado } 714253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 715168d1b1aSCarson Labrado { 716168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 717168d1b1aSCarson Labrado systemName); 718168d1b1aSCarson Labrado return; 719168d1b1aSCarson Labrado } 720168d1b1aSCarson Labrado 721168d1b1aSCarson Labrado std::string entryPath = 722168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 723168d1b1aSCarson Labrado entryID; 724168d1b1aSCarson Labrado 725168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 726168d1b1aSCarson Labrado [asyncResp, entryID, 727168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 728168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 729168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 730168d1b1aSCarson Labrado }; 731168d1b1aSCarson Labrado 732168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 733168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 734168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 735168d1b1aSCarson Labrado } 736168d1b1aSCarson Labrado 7378e31778eSAsmitha Karunanithi inline DumpCreationProgress 7388e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 739a43be80fSAsmitha Karunanithi { 7408e31778eSAsmitha Karunanithi if (status == 7418e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 7428e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 7438e31778eSAsmitha Karunanithi { 7448e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7458e31778eSAsmitha Karunanithi } 7468e31778eSAsmitha Karunanithi if (status == 7478e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 7488e31778eSAsmitha Karunanithi { 7498e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 7508e31778eSAsmitha Karunanithi } 7518e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7528e31778eSAsmitha Karunanithi } 7538e31778eSAsmitha Karunanithi 7548e31778eSAsmitha Karunanithi inline DumpCreationProgress 7558e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 7568e31778eSAsmitha Karunanithi { 7578e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 7588e31778eSAsmitha Karunanithi { 7598e31778eSAsmitha Karunanithi if (key == "Status") 7608e31778eSAsmitha Karunanithi { 7618e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 7628e31778eSAsmitha Karunanithi if (value == nullptr) 7638e31778eSAsmitha Karunanithi { 76462598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 7658e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7668e31778eSAsmitha Karunanithi } 7678e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 7688e31778eSAsmitha Karunanithi } 7698e31778eSAsmitha Karunanithi } 7708e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7718e31778eSAsmitha Karunanithi } 7728e31778eSAsmitha Karunanithi 7738e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7748e31778eSAsmitha Karunanithi { 7758e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7768e31778eSAsmitha Karunanithi { 777253f11b8SEd Tanous return std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 7789f565090SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 7798e31778eSAsmitha Karunanithi } 7808e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7818e31778eSAsmitha Karunanithi { 782253f11b8SEd Tanous return std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 783253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 7848e31778eSAsmitha Karunanithi } 7858e31778eSAsmitha Karunanithi return ""; 7868e31778eSAsmitha Karunanithi } 7878e31778eSAsmitha Karunanithi 7888e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7898e31778eSAsmitha Karunanithi task::Payload&& payload, 7908e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7918e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7928e31778eSAsmitha Karunanithi { 7938e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7948e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7958e31778eSAsmitha Karunanithi 7968e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7978e31778eSAsmitha Karunanithi 7988e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7998e31778eSAsmitha Karunanithi { 80062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 8018e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8028e31778eSAsmitha Karunanithi return; 8038e31778eSAsmitha Karunanithi } 8048e31778eSAsmitha Karunanithi 8058e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 8068cb2c024SEd Tanous [asyncResp, payload = std::move(payload), createdObjPath, 8078e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 8085e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 8098e31778eSAsmitha Karunanithi const std::string& introspectXml) { 8108e31778eSAsmitha Karunanithi if (ec) 8118e31778eSAsmitha Karunanithi { 81262598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 81362598e31SEd Tanous ec.message()); 8148e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8158e31778eSAsmitha Karunanithi return; 8168e31778eSAsmitha Karunanithi } 8178e31778eSAsmitha Karunanithi 8188e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 8198e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 8208e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 8218e31778eSAsmitha Karunanithi // Else, return task completed. 8228e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 8238e31778eSAsmitha Karunanithi 8248e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 8258e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 8268e31778eSAsmitha Karunanithi if (pRoot == nullptr) 8278e31778eSAsmitha Karunanithi { 82862598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 8298e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8308e31778eSAsmitha Karunanithi return; 8318e31778eSAsmitha Karunanithi } 8328e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 8338e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 8348e31778eSAsmitha Karunanithi 8358e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 8368e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 8378e31778eSAsmitha Karunanithi { 8388e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 8398e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 8408e31778eSAsmitha Karunanithi { 8418e31778eSAsmitha Karunanithi if (thisInterfaceName == 8428e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 8438e31778eSAsmitha Karunanithi { 8448e31778eSAsmitha Karunanithi interfaceNode = 8458e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 8468e31778eSAsmitha Karunanithi continue; 8478e31778eSAsmitha Karunanithi } 8488e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 8498e31778eSAsmitha Karunanithi break; 8508e31778eSAsmitha Karunanithi } 8518e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 8528e31778eSAsmitha Karunanithi } 8538e31778eSAsmitha Karunanithi 854a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 8558e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 8568b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 857a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 8588b24275dSEd Tanous if (ec2) 859cb13a392SEd Tanous { 86062598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 86162598e31SEd Tanous createdObjPath.str); 8628e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 8636145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 8646145ed6fSAsmitha Karunanithi return task::completed; 865cb13a392SEd Tanous } 866b9d36b47SEd Tanous 8678e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 868a43be80fSAsmitha Karunanithi { 8698e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8708e31778eSAsmitha Karunanithi std::string prop; 8718e31778eSAsmitha Karunanithi msg.read(prop, values); 8728e31778eSAsmitha Karunanithi 8738e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8748e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8758e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8768e31778eSAsmitha Karunanithi { 87762598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 87862598e31SEd Tanous createdObjPath.str); 8798e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8808e31778eSAsmitha Karunanithi return task::completed; 8818e31778eSAsmitha Karunanithi } 8828e31778eSAsmitha Karunanithi 8838e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8848e31778eSAsmitha Karunanithi { 88562598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 88662598e31SEd Tanous createdObjPath.str); 8878e31778eSAsmitha Karunanithi return !task::completed; 8888e31778eSAsmitha Karunanithi } 8898e31778eSAsmitha Karunanithi } 8908e31778eSAsmitha Karunanithi 891a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 892a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 893a43be80fSAsmitha Karunanithi 894c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 895253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump/Entries/{}", 896253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, dumpId); 897c51a58eeSEd Tanous 898c51a58eeSEd Tanous std::string headerLoc = "Location: "; 899c51a58eeSEd Tanous headerLoc += url.buffer(); 900c51a58eeSEd Tanous 901002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 902a43be80fSAsmitha Karunanithi 90362598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 90462598e31SEd Tanous createdObjPath.str); 905a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 906b47452b2SAsmitha Karunanithi return task::completed; 907a43be80fSAsmitha Karunanithi }, 9088e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 9098e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 9108e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 911a43be80fSAsmitha Karunanithi 9128e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 9138e31778eSAsmitha Karunanithi // requested dump will be collected. 9148e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 915a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 9168e31778eSAsmitha Karunanithi task->payload.emplace(payload); 9178e31778eSAsmitha Karunanithi }, 9188e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 9198e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 920a43be80fSAsmitha Karunanithi } 921a43be80fSAsmitha Karunanithi 9228d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9238d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 924a43be80fSAsmitha Karunanithi { 925fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 926fdd26906SClaire Weinan if (dumpPath.empty()) 927a43be80fSAsmitha Karunanithi { 928a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 929a43be80fSAsmitha Karunanithi return; 930a43be80fSAsmitha Karunanithi } 931a43be80fSAsmitha Karunanithi 932a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 933a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 934a43be80fSAsmitha Karunanithi 93515ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 936a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 937a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 938a43be80fSAsmitha Karunanithi { 939a43be80fSAsmitha Karunanithi return; 940a43be80fSAsmitha Karunanithi } 941a43be80fSAsmitha Karunanithi 942a43be80fSAsmitha Karunanithi if (dumpType == "System") 943a43be80fSAsmitha Karunanithi { 944a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 945a43be80fSAsmitha Karunanithi { 94662598e31SEd Tanous BMCWEB_LOG_ERROR( 94762598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 948a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 949a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 950a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 951a43be80fSAsmitha Karunanithi return; 952a43be80fSAsmitha Karunanithi } 9533174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 954a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 955a43be80fSAsmitha Karunanithi { 95662598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 957ace85d60SEd Tanous messages::internalError(asyncResp->res); 958a43be80fSAsmitha Karunanithi return; 959a43be80fSAsmitha Karunanithi } 960253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump/", 961253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 962a43be80fSAsmitha Karunanithi } 963a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 964a43be80fSAsmitha Karunanithi { 965a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 966a43be80fSAsmitha Karunanithi { 96762598e31SEd Tanous BMCWEB_LOG_ERROR( 96862598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 969a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 970a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 971a43be80fSAsmitha Karunanithi return; 972a43be80fSAsmitha Karunanithi } 9733174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 974a43be80fSAsmitha Karunanithi { 97562598e31SEd Tanous BMCWEB_LOG_ERROR( 97662598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 977ace85d60SEd Tanous messages::internalError(asyncResp->res); 978a43be80fSAsmitha Karunanithi return; 979a43be80fSAsmitha Karunanithi } 980253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump/", 981253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 9825907571dSAsmitha Karunanithi } 9835907571dSAsmitha Karunanithi else 9845907571dSAsmitha Karunanithi { 98562598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 9865907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9875907571dSAsmitha Karunanithi return; 988a43be80fSAsmitha Karunanithi } 989a43be80fSAsmitha Karunanithi 9908e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9918e31778eSAsmitha Karunanithi createDumpParamVec; 9928e31778eSAsmitha Karunanithi 993f574a8e1SCarson Labrado if (req.session != nullptr) 994f574a8e1SCarson Labrado { 99568dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 99668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 99768dd075aSAsmitha Karunanithi req.session->clientIp); 99868dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 99968dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 100068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1001f574a8e1SCarson Labrado } 100268dd075aSAsmitha Karunanithi 1003a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 10045e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 10055e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 10065e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 10078e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1008a43be80fSAsmitha Karunanithi if (ec) 1009a43be80fSAsmitha Karunanithi { 101062598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 10115907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 10125907571dSAsmitha Karunanithi if (dbusError == nullptr) 10135907571dSAsmitha Karunanithi { 10145907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 10155907571dSAsmitha Karunanithi return; 10165907571dSAsmitha Karunanithi } 10175907571dSAsmitha Karunanithi 101862598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 101962598e31SEd Tanous dbusError->name, dbusError->message); 10205907571dSAsmitha Karunanithi if (std::string_view( 10215907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 10225907571dSAsmitha Karunanithi dbusError->name) 10235907571dSAsmitha Karunanithi { 10245907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 10255907571dSAsmitha Karunanithi return; 10265907571dSAsmitha Karunanithi } 10275907571dSAsmitha Karunanithi if (std::string_view( 10285907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 10295907571dSAsmitha Karunanithi dbusError->name) 10305907571dSAsmitha Karunanithi { 10315907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 10325907571dSAsmitha Karunanithi return; 10335907571dSAsmitha Karunanithi } 10345907571dSAsmitha Karunanithi if (std::string_view( 10355907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 10365907571dSAsmitha Karunanithi dbusError->name) 10375907571dSAsmitha Karunanithi { 10385907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 10395907571dSAsmitha Karunanithi return; 10405907571dSAsmitha Karunanithi } 10415907571dSAsmitha Karunanithi // Other Dbus errors such as: 10425907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 10435907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 10445907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 10455907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 10465907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 10475907571dSAsmitha Karunanithi // back to the client. 1048a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1049a43be80fSAsmitha Karunanithi return; 1050a43be80fSAsmitha Karunanithi } 105162598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 10528e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1053a43be80fSAsmitha Karunanithi }, 105418f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10558e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1056a43be80fSAsmitha Karunanithi } 1057a43be80fSAsmitha Karunanithi 10588d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10598d1b46d7Szhanghch05 const std::string& dumpType) 106080319af1SAsmitha Karunanithi { 10610d946211SClaire Weinan crow::connections::systemBus->async_method_call( 10620d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 106380319af1SAsmitha Karunanithi if (ec) 106480319af1SAsmitha Karunanithi { 106562598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 106680319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 106780319af1SAsmitha Karunanithi return; 106880319af1SAsmitha Karunanithi } 10690d946211SClaire Weinan }, 107018f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10710d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 107280319af1SAsmitha Karunanithi } 107380319af1SAsmitha Karunanithi 1074df254f2cSEd Tanous inline void 1075b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1076b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1077b9d36b47SEd Tanous std::string& logfile) 1078043a0536SJohnathan Mantey { 1079d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1080d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1081d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1082d1bde9e5SKrzysztof Grobelny 1083d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1084d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1085d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1086d1bde9e5SKrzysztof Grobelny 1087d1bde9e5SKrzysztof Grobelny if (!success) 1088043a0536SJohnathan Mantey { 1089d1bde9e5SKrzysztof Grobelny return; 1090043a0536SJohnathan Mantey } 1091d1bde9e5SKrzysztof Grobelny 1092d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1093043a0536SJohnathan Mantey { 1094d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1095d1bde9e5SKrzysztof Grobelny } 1096d1bde9e5SKrzysztof Grobelny 1097d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1098043a0536SJohnathan Mantey { 1099d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1100043a0536SJohnathan Mantey } 1101d1bde9e5SKrzysztof Grobelny 1102d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1103043a0536SJohnathan Mantey { 1104d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1105043a0536SJohnathan Mantey } 1106043a0536SJohnathan Mantey } 1107043a0536SJohnathan Mantey 11087e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 11091da66f75SEd Tanous { 1110c4bf6374SJason M. Bills /** 1111c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1112c4bf6374SJason M. Bills */ 111322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1114ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1115002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1116002d39b4SEd Tanous [&app](const crow::Request& req, 111722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 111822d268cbSEd Tanous const std::string& systemName) { 11193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1120c4bf6374SJason M. Bills { 112145ca1b86SEd Tanous return; 112245ca1b86SEd Tanous } 112325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 11247f3e84a1SEd Tanous { 11257f3e84a1SEd Tanous // Option currently returns no systems. TBD 11267f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 11277f3e84a1SEd Tanous systemName); 11287f3e84a1SEd Tanous return; 11297f3e84a1SEd Tanous } 1130253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 113122d268cbSEd Tanous { 113222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 113322d268cbSEd Tanous systemName); 113422d268cbSEd Tanous return; 113522d268cbSEd Tanous } 113622d268cbSEd Tanous 11377e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 11387e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1139c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1140c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1141c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1142253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices", 1143253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 114445ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1145c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1146c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1147002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1148c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11491476687dSEd Tanous nlohmann::json::object_t eventLog; 11501476687dSEd Tanous eventLog["@odata.id"] = 1151253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1152253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1153b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 115425b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 115525b54dbaSEd Tanous { 11561476687dSEd Tanous nlohmann::json::object_t dumpLog; 115725b54dbaSEd Tanous dumpLog["@odata.id"] = 1158253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump", 1159253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1160b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 116125b54dbaSEd Tanous } 1162c9bb6861Sraviteja-b 11635ffd11f2SGunnar Mills if constexpr (BMCWEB_REDFISH_CPU_LOG) 116425b54dbaSEd Tanous { 11651476687dSEd Tanous nlohmann::json::object_t crashdump; 11661476687dSEd Tanous crashdump["@odata.id"] = 1167253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 1168253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1169b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 117025b54dbaSEd Tanous } 1171b7028ebfSSpencer Ku 117225b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_HOST_LOGGER) 117325b54dbaSEd Tanous { 11741476687dSEd Tanous nlohmann::json::object_t hostlogger; 11751476687dSEd Tanous hostlogger["@odata.id"] = 1176253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 1177253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1178b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 117925b54dbaSEd Tanous } 1180c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1181c4bf6374SJason M. Bills logServiceArray.size(); 1182a3316fc6SZhikuiRen 11837a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11847a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11857a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11867a1dbc48SGeorge Liu "/", 0, interfaces, 11877a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1188b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1189b9d36b47SEd Tanous subtreePath) { 1190a3316fc6SZhikuiRen if (ec) 1191a3316fc6SZhikuiRen { 119262598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1193a3316fc6SZhikuiRen return; 1194a3316fc6SZhikuiRen } 1195a3316fc6SZhikuiRen 119655f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1197a3316fc6SZhikuiRen { 1198a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1199a3316fc6SZhikuiRen { 120023a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1201a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1202613dabeaSEd Tanous nlohmann::json::object_t member; 1203253f11b8SEd Tanous member["@odata.id"] = std::format( 1204253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes", 1205253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1206613dabeaSEd Tanous 1207b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1208613dabeaSEd Tanous 120945ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 121023a21a1cSEd Tanous logServiceArrayLocal.size(); 1211a3316fc6SZhikuiRen return; 1212a3316fc6SZhikuiRen } 1213a3316fc6SZhikuiRen } 12147a1dbc48SGeorge Liu }); 12157e860f15SJohn Edward Broadbent }); 1216c4bf6374SJason M. Bills } 1217c4bf6374SJason M. Bills 12187e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1219c4bf6374SJason M. Bills { 122022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1221ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1222002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1223002d39b4SEd Tanous [&app](const crow::Request& req, 122422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 122522d268cbSEd Tanous const std::string& systemName) { 12263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 122745ca1b86SEd Tanous { 122845ca1b86SEd Tanous return; 122945ca1b86SEd Tanous } 1230253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 123122d268cbSEd Tanous { 123222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 123322d268cbSEd Tanous systemName); 123422d268cbSEd Tanous return; 123522d268cbSEd Tanous } 1236c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1237253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1238253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1239c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1240b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1241c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1242002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1243c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1244c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 12457c8c4058STejas Patil 12467c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 12472b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 12487c8c4058STejas Patil 12497c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 12507c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 12517c8c4058STejas Patil redfishDateTimeOffset.second; 12527c8c4058STejas Patil 12531476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 1254253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1255253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 125620fa6a2cSEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] 1257e7d6c8b2SGunnar Mills 125820fa6a2cSEd Tanous = std::format( 1259253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog", 126020fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 12617e860f15SJohn Edward Broadbent }); 1262489640c6SJason M. Bills } 1263489640c6SJason M. Bills 12647e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1265489640c6SJason M. Bills { 12664978b63fSJason M. Bills BMCWEB_ROUTE( 12674978b63fSJason M. Bills app, 126822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1269432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 12707e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 127145ca1b86SEd Tanous [&app](const crow::Request& req, 127222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 127322d268cbSEd Tanous const std::string& systemName) { 12743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 127545ca1b86SEd Tanous { 127645ca1b86SEd Tanous return; 127745ca1b86SEd Tanous } 1278253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 127922d268cbSEd Tanous { 128022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 128122d268cbSEd Tanous systemName); 128222d268cbSEd Tanous return; 128322d268cbSEd Tanous } 1284489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1285489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1286489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1287489640c6SJason M. Bills { 1288489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1289489640c6SJason M. Bills { 1290489640c6SJason M. Bills std::error_code ec; 1291489640c6SJason M. Bills std::filesystem::remove(file, ec); 1292489640c6SJason M. Bills } 1293489640c6SJason M. Bills } 1294489640c6SJason M. Bills 1295489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1296489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 12975e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1298489640c6SJason M. Bills if (ec) 1299489640c6SJason M. Bills { 130062598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1301489640c6SJason M. Bills messages::internalError(asyncResp->res); 1302489640c6SJason M. Bills return; 1303489640c6SJason M. Bills } 1304489640c6SJason M. Bills 1305489640c6SJason M. Bills messages::success(asyncResp->res); 1306489640c6SJason M. Bills }, 1307489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1308002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1309002d39b4SEd Tanous "replace"); 13107e860f15SJohn Edward Broadbent }); 1311c4bf6374SJason M. Bills } 1312c4bf6374SJason M. Bills 1313ac992cdeSJason M. Bills enum class LogParseError 1314ac992cdeSJason M. Bills { 1315ac992cdeSJason M. Bills success, 1316ac992cdeSJason M. Bills parseFailed, 1317ac992cdeSJason M. Bills messageIdNotInRegistry, 1318ac992cdeSJason M. Bills }; 1319ac992cdeSJason M. Bills 1320ac992cdeSJason M. Bills static LogParseError 1321ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1322b5a76932SEd Tanous const std::string& logEntry, 1323de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1324c4bf6374SJason M. Bills { 132595820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1326cd225da8SJason M. Bills // First get the Timestamp 1327f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1328cd225da8SJason M. Bills if (space == std::string::npos) 132995820184SJason M. Bills { 1330ac992cdeSJason M. Bills return LogParseError::parseFailed; 133195820184SJason M. Bills } 1332cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1333cd225da8SJason M. Bills // Then get the log contents 1334f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1335cd225da8SJason M. Bills if (entryStart == std::string::npos) 1336cd225da8SJason M. Bills { 1337ac992cdeSJason M. Bills return LogParseError::parseFailed; 1338cd225da8SJason M. Bills } 1339cd225da8SJason M. Bills std::string_view entry(logEntry); 1340cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1341cd225da8SJason M. Bills // Use split to separate the entry into its fields 1342cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 134350ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1344cd225da8SJason M. Bills // We need at least a MessageId to be valid 13451e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 13461e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1347cd225da8SJason M. Bills { 1348ac992cdeSJason M. Bills return LogParseError::parseFailed; 1349cd225da8SJason M. Bills } 13501e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 13514851d45dSJason M. Bills // Get the Message from the MessageRegistry 1352fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1353c4bf6374SJason M. Bills 13541e6deaf6SEd Tanous logEntryIter++; 135554417b02SSui Chen if (message == nullptr) 1356c4bf6374SJason M. Bills { 135762598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1358ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1359c4bf6374SJason M. Bills } 1360c4bf6374SJason M. Bills 13611e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 13621e6deaf6SEd Tanous logEntryFields.end()); 1363c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1364c05bba45SEd Tanous 13651e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 13661e6deaf6SEd Tanous message->message); 13671e6deaf6SEd Tanous if (msg.empty()) 136815a86ff6SJason M. Bills { 13691e6deaf6SEd Tanous return LogParseError::parseFailed; 137015a86ff6SJason M. Bills } 13714851d45dSJason M. Bills 137295820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 137395820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 137495820184SJason M. Bills // between the '.' and the '+', so just remove them. 1375f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1376f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 137795820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1378c4bf6374SJason M. Bills { 137995820184SJason M. Bills timestamp.erase(dot, plus - dot); 1380c4bf6374SJason M. Bills } 1381c4bf6374SJason M. Bills 1382c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13839c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1384ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1385253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1386253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 138784afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 138884afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 138984afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 139084afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 139184afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 139284afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 139384afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 139484afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1395ac992cdeSJason M. Bills return LogParseError::success; 1396c4bf6374SJason M. Bills } 1397c4bf6374SJason M. Bills 13987e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1399c4bf6374SJason M. Bills { 140022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 14018b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1402002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1403002d39b4SEd Tanous [&app](const crow::Request& req, 140422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 140522d268cbSEd Tanous const std::string& systemName) { 1406c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1407c937d2bfSEd Tanous .canDelegateTop = true, 1408c937d2bfSEd Tanous .canDelegateSkip = true, 1409c937d2bfSEd Tanous }; 1410c937d2bfSEd Tanous query_param::Query delegatedQuery; 1411c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 14123ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1413c4bf6374SJason M. Bills { 1414c4bf6374SJason M. Bills return; 1415c4bf6374SJason M. Bills } 141625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 14177f3e84a1SEd Tanous { 14187f3e84a1SEd Tanous // Option currently returns no systems. TBD 14197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 14207f3e84a1SEd Tanous systemName); 14217f3e84a1SEd Tanous return; 14227f3e84a1SEd Tanous } 1423253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 142422d268cbSEd Tanous { 142522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 142622d268cbSEd Tanous systemName); 142722d268cbSEd Tanous return; 142822d268cbSEd Tanous } 142922d268cbSEd Tanous 14305143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 14313648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 14323648c8beSEd Tanous 14337e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 14347e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1435c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1436c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1437c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1438253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1439253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1440c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1441c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1442c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1443cb92c03bSAndrew Geissler 14444978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1445c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 14467e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 14477e860f15SJohn Edward Broadbent // entry 144895820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 144995820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1450b01bf299SEd Tanous uint64_t entryCount = 0; 1451cd225da8SJason M. Bills std::string logEntry; 145295820184SJason M. Bills 14537e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14547e860f15SJohn Edward Broadbent // backwards 1455002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1456002d39b4SEd Tanous it++) 1457c4bf6374SJason M. Bills { 1458cd225da8SJason M. Bills std::ifstream logStream(*it); 145995820184SJason M. Bills if (!logStream.is_open()) 1460c4bf6374SJason M. Bills { 1461c4bf6374SJason M. Bills continue; 1462c4bf6374SJason M. Bills } 1463c4bf6374SJason M. Bills 1464e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1465e85d6b16SJason M. Bills bool firstEntry = true; 146695820184SJason M. Bills while (std::getline(logStream, logEntry)) 146795820184SJason M. Bills { 1468c4bf6374SJason M. Bills std::string idStr; 1469e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1470c4bf6374SJason M. Bills { 1471c4bf6374SJason M. Bills continue; 1472c4bf6374SJason M. Bills } 1473e85d6b16SJason M. Bills firstEntry = false; 1474e85d6b16SJason M. Bills 1475de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 147689492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 147789492a15SPatrick Williams bmcLogEntry); 1478ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1479ac992cdeSJason M. Bills { 1480ac992cdeSJason M. Bills continue; 1481ac992cdeSJason M. Bills } 1482ac992cdeSJason M. Bills if (status != LogParseError::success) 1483c4bf6374SJason M. Bills { 1484c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1485c4bf6374SJason M. Bills return; 1486c4bf6374SJason M. Bills } 1487de703c5dSJason M. Bills 1488de703c5dSJason M. Bills entryCount++; 1489de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1490de703c5dSJason M. Bills // start) and top (number of entries to display) 14913648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1492de703c5dSJason M. Bills { 1493de703c5dSJason M. Bills continue; 1494de703c5dSJason M. Bills } 1495de703c5dSJason M. Bills 1496b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1497c4bf6374SJason M. Bills } 149895820184SJason M. Bills } 1499c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 15003648c8beSEd Tanous if (skip + top < entryCount) 1501c4bf6374SJason M. Bills { 1502253f11b8SEd Tanous asyncResp->res 1503253f11b8SEd Tanous .jsonValue["Members@odata.nextLink"] = boost::urls::format( 1504253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}", 1505253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top)); 1506c4bf6374SJason M. Bills } 15077e860f15SJohn Edward Broadbent }); 1508897967deSJason M. Bills } 1509897967deSJason M. Bills 15107e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1511897967deSJason M. Bills { 15127e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 151322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1514ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 15157e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 151645ca1b86SEd Tanous [&app](const crow::Request& req, 15177e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 151822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 15193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 152045ca1b86SEd Tanous { 152145ca1b86SEd Tanous return; 152245ca1b86SEd Tanous } 152325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 15247f3e84a1SEd Tanous { 15257f3e84a1SEd Tanous // Option currently returns no systems. TBD 15267f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15277f3e84a1SEd Tanous systemName); 15287f3e84a1SEd Tanous return; 15297f3e84a1SEd Tanous } 153022d268cbSEd Tanous 1531253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 153222d268cbSEd Tanous { 153322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 153422d268cbSEd Tanous systemName); 153522d268cbSEd Tanous return; 153622d268cbSEd Tanous } 153722d268cbSEd Tanous 15387e860f15SJohn Edward Broadbent const std::string& targetID = param; 15398d1b46d7Szhanghch05 15407e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 15417e860f15SJohn Edward Broadbent // entry to find the target entry 1542897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1543897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1544897967deSJason M. Bills std::string logEntry; 1545897967deSJason M. Bills 15467e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15477e860f15SJohn Edward Broadbent // backwards 1548002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1549002d39b4SEd Tanous it++) 1550897967deSJason M. Bills { 1551897967deSJason M. Bills std::ifstream logStream(*it); 1552897967deSJason M. Bills if (!logStream.is_open()) 1553897967deSJason M. Bills { 1554897967deSJason M. Bills continue; 1555897967deSJason M. Bills } 1556897967deSJason M. Bills 1557897967deSJason M. Bills // Reset the unique ID on the first entry 1558897967deSJason M. Bills bool firstEntry = true; 1559897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1560897967deSJason M. Bills { 1561897967deSJason M. Bills std::string idStr; 1562897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1563897967deSJason M. Bills { 1564897967deSJason M. Bills continue; 1565897967deSJason M. Bills } 1566897967deSJason M. Bills firstEntry = false; 1567897967deSJason M. Bills 1568897967deSJason M. Bills if (idStr == targetID) 1569897967deSJason M. Bills { 1570de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1571ac992cdeSJason M. Bills LogParseError status = 1572ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1573ac992cdeSJason M. Bills if (status != LogParseError::success) 1574897967deSJason M. Bills { 1575897967deSJason M. Bills messages::internalError(asyncResp->res); 1576897967deSJason M. Bills return; 1577897967deSJason M. Bills } 1578d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1579897967deSJason M. Bills return; 1580897967deSJason M. Bills } 1581897967deSJason M. Bills } 1582897967deSJason M. Bills } 1583897967deSJason M. Bills // Requested ID was not found 15849db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15857e860f15SJohn Edward Broadbent }); 158608a4e4b5SAnthony Wilson } 158708a4e4b5SAnthony Wilson 15887e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 158908a4e4b5SAnthony Wilson { 159022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1591ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1592002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1593002d39b4SEd Tanous [&app](const crow::Request& req, 159422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 159522d268cbSEd Tanous const std::string& systemName) { 15963ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 159745ca1b86SEd Tanous { 159845ca1b86SEd Tanous return; 159945ca1b86SEd Tanous } 160025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 16017f3e84a1SEd Tanous { 16027f3e84a1SEd Tanous // Option currently returns no systems. TBD 16037f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16047f3e84a1SEd Tanous systemName); 16057f3e84a1SEd Tanous return; 16067f3e84a1SEd Tanous } 1607253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 160822d268cbSEd Tanous { 160922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 161022d268cbSEd Tanous systemName); 161122d268cbSEd Tanous return; 161222d268cbSEd Tanous } 161322d268cbSEd Tanous 16147e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 16157e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 161608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 161708a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 161808a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 1619253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1620253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 162108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 162208a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 162308a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 162408a4e4b5SAnthony Wilson 1625cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1626cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 16275eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 16285eb468daSGeorge Liu dbus::utility::getManagedObjects( 16295eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 16305e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1631914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1632cb92c03bSAndrew Geissler if (ec) 1633cb92c03bSAndrew Geissler { 1634cb92c03bSAndrew Geissler // TODO Handle for specific error code 163562598e31SEd Tanous BMCWEB_LOG_ERROR( 163662598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1637cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1638cb92c03bSAndrew Geissler return; 1639cb92c03bSAndrew Geissler } 16403544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 16419eb808c1SEd Tanous for (const auto& objectPath : resp) 1642cb92c03bSAndrew Geissler { 1643914e2d5dSEd Tanous const uint32_t* id = nullptr; 1644c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1645c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1646914e2d5dSEd Tanous const std::string* severity = nullptr; 1647914e2d5dSEd Tanous const std::string* message = nullptr; 1648914e2d5dSEd Tanous const std::string* filePath = nullptr; 16499c11a172SVijay Lobo const std::string* resolution = nullptr; 165075710de2SXiaochao Ma bool resolved = false; 16519017faf2SAbhishek Patel const std::string* notify = nullptr; 16529017faf2SAbhishek Patel 16539eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1654f86bb901SAdriana Kobylak { 1655f86bb901SAdriana Kobylak if (interfaceMap.first == 1656f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1657f86bb901SAdriana Kobylak { 1658002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1659cb92c03bSAndrew Geissler { 1660cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1661cb92c03bSAndrew Geissler { 1662002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1663cb92c03bSAndrew Geissler } 1664cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1665cb92c03bSAndrew Geissler { 1666002d39b4SEd Tanous timestamp = 1667002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16687e860f15SJohn Edward Broadbent } 1669002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 16707e860f15SJohn Edward Broadbent { 1671002d39b4SEd Tanous updateTimestamp = 1672002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16737e860f15SJohn Edward Broadbent } 16747e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 16757e860f15SJohn Edward Broadbent { 16767e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 16777e860f15SJohn Edward Broadbent &propertyMap.second); 16787e860f15SJohn Edward Broadbent } 16799c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 16809c11a172SVijay Lobo { 16819c11a172SVijay Lobo resolution = std::get_if<std::string>( 16829c11a172SVijay Lobo &propertyMap.second); 16839c11a172SVijay Lobo } 16847e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 16857e860f15SJohn Edward Broadbent { 16867e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 16877e860f15SJohn Edward Broadbent &propertyMap.second); 16887e860f15SJohn Edward Broadbent } 16897e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 16907e860f15SJohn Edward Broadbent { 1691914e2d5dSEd Tanous const bool* resolveptr = 1692002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16937e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16947e860f15SJohn Edward Broadbent { 1695002d39b4SEd Tanous messages::internalError(asyncResp->res); 16967e860f15SJohn Edward Broadbent return; 16977e860f15SJohn Edward Broadbent } 16987e860f15SJohn Edward Broadbent resolved = *resolveptr; 16997e860f15SJohn Edward Broadbent } 17009017faf2SAbhishek Patel else if (propertyMap.first == 17019017faf2SAbhishek Patel "ServiceProviderNotify") 17029017faf2SAbhishek Patel { 17039017faf2SAbhishek Patel notify = std::get_if<std::string>( 17049017faf2SAbhishek Patel &propertyMap.second); 17059017faf2SAbhishek Patel if (notify == nullptr) 17069017faf2SAbhishek Patel { 17079017faf2SAbhishek Patel messages::internalError(asyncResp->res); 17089017faf2SAbhishek Patel return; 17099017faf2SAbhishek Patel } 17109017faf2SAbhishek Patel } 17117e860f15SJohn Edward Broadbent } 17127e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 17137e860f15SJohn Edward Broadbent severity == nullptr) 17147e860f15SJohn Edward Broadbent { 17157e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17167e860f15SJohn Edward Broadbent return; 17177e860f15SJohn Edward Broadbent } 17187e860f15SJohn Edward Broadbent } 17197e860f15SJohn Edward Broadbent else if (interfaceMap.first == 17207e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 17217e860f15SJohn Edward Broadbent { 1722002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 17237e860f15SJohn Edward Broadbent { 17247e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 17257e860f15SJohn Edward Broadbent { 17267e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 17277e860f15SJohn Edward Broadbent &propertyMap.second); 17287e860f15SJohn Edward Broadbent } 17297e860f15SJohn Edward Broadbent } 17307e860f15SJohn Edward Broadbent } 17317e860f15SJohn Edward Broadbent } 17327e860f15SJohn Edward Broadbent // Object path without the 17337e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 17347e860f15SJohn Edward Broadbent // and continue. 17357e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1736c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1737c419c759SEd Tanous updateTimestamp == nullptr) 17387e860f15SJohn Edward Broadbent { 17397e860f15SJohn Edward Broadbent continue; 17407e860f15SJohn Edward Broadbent } 17413544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 17429c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1743ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1744253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1745253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 17467e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 17477e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 17487e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 17497e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 17509c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17519c11a172SVijay Lobo { 17529c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 17539c11a172SVijay Lobo } 17549017faf2SAbhishek Patel std::optional<bool> notifyAction = 17559017faf2SAbhishek Patel getProviderNotifyAction(*notify); 17569017faf2SAbhishek Patel if (notifyAction) 17579017faf2SAbhishek Patel { 17589017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 17599017faf2SAbhishek Patel } 17607e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 17617e860f15SJohn Edward Broadbent thisEntry["Severity"] = 17627e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 17637e860f15SJohn Edward Broadbent thisEntry["Created"] = 17642b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 17657e860f15SJohn Edward Broadbent thisEntry["Modified"] = 17662b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 17677e860f15SJohn Edward Broadbent if (filePath != nullptr) 17687e860f15SJohn Edward Broadbent { 17697e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 1770253f11b8SEd Tanous std::format( 1771253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 1772253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 17737e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 17747e860f15SJohn Edward Broadbent } 17757e860f15SJohn Edward Broadbent } 17763544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 17773544d2a7SEd Tanous const nlohmann::json& right) { 17787e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 17797e860f15SJohn Edward Broadbent }); 17807e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 17817e860f15SJohn Edward Broadbent entriesArray.size(); 17823544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 17835eb468daSGeorge Liu }); 17847e860f15SJohn Edward Broadbent }); 17857e860f15SJohn Edward Broadbent } 17867e860f15SJohn Edward Broadbent 17877e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 17887e860f15SJohn Edward Broadbent { 17897e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 179022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1791ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1792002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1793002d39b4SEd Tanous [&app](const crow::Request& req, 17947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 179522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17963ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17977e860f15SJohn Edward Broadbent { 179845ca1b86SEd Tanous return; 179945ca1b86SEd Tanous } 180025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 18017f3e84a1SEd Tanous { 18027f3e84a1SEd Tanous // Option currently returns no systems. TBD 18037f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 18047f3e84a1SEd Tanous systemName); 18057f3e84a1SEd Tanous return; 18067f3e84a1SEd Tanous } 1807253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 180822d268cbSEd Tanous { 180922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 181022d268cbSEd Tanous systemName); 181122d268cbSEd Tanous return; 181222d268cbSEd Tanous } 181322d268cbSEd Tanous 18147e860f15SJohn Edward Broadbent std::string entryID = param; 18157e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 18167e860f15SJohn Edward Broadbent 18177e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 18187e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1819d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1820d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1821d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 18225e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1823b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 18247e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 18257e860f15SJohn Edward Broadbent { 1826d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1827d1bde9e5SKrzysztof Grobelny entryID); 18287e860f15SJohn Edward Broadbent return; 18297e860f15SJohn Edward Broadbent } 18307e860f15SJohn Edward Broadbent if (ec) 18317e860f15SJohn Edward Broadbent { 183262598e31SEd Tanous BMCWEB_LOG_ERROR( 183362598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 18347e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18357e860f15SJohn Edward Broadbent return; 18367e860f15SJohn Edward Broadbent } 1837914e2d5dSEd Tanous const uint32_t* id = nullptr; 1838c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1839c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1840914e2d5dSEd Tanous const std::string* severity = nullptr; 1841914e2d5dSEd Tanous const std::string* message = nullptr; 1842914e2d5dSEd Tanous const std::string* filePath = nullptr; 18439c11a172SVijay Lobo const std::string* resolution = nullptr; 18447e860f15SJohn Edward Broadbent bool resolved = false; 18459017faf2SAbhishek Patel const std::string* notify = nullptr; 18467e860f15SJohn Edward Broadbent 1847d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1848d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1849d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 18509c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 18519017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 18529017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1853d1bde9e5SKrzysztof Grobelny 1854d1bde9e5SKrzysztof Grobelny if (!success) 185575710de2SXiaochao Ma { 185675710de2SXiaochao Ma messages::internalError(asyncResp->res); 185775710de2SXiaochao Ma return; 185875710de2SXiaochao Ma } 1859d1bde9e5SKrzysztof Grobelny 1860002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 18619017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 18629017faf2SAbhishek Patel notify == nullptr) 1863f86bb901SAdriana Kobylak { 1864ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1865271584abSEd Tanous return; 1866271584abSEd Tanous } 18679017faf2SAbhishek Patel 1868f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 18699c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1870ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1871253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1872253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 187345ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1874f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1875f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1876f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 18779017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 18789017faf2SAbhishek Patel if (notifyAction) 18799017faf2SAbhishek Patel { 18809017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 18819017faf2SAbhishek Patel *notifyAction; 18829017faf2SAbhishek Patel } 18839c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18849c11a172SVijay Lobo { 18859c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 18869c11a172SVijay Lobo } 1887f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1888f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1889f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1890f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 18912b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1892f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 18932b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1894f86bb901SAdriana Kobylak if (filePath != nullptr) 1895f86bb901SAdriana Kobylak { 1896f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1897253f11b8SEd Tanous std::format( 1898253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 1899253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 1900e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1901f86bb901SAdriana Kobylak } 1902d1bde9e5SKrzysztof Grobelny }); 19037e860f15SJohn Edward Broadbent }); 1904336e96c6SChicago Duan 19057e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 190622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1907ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 19087e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 190945ca1b86SEd Tanous [&app](const crow::Request& req, 19107e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 191122d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 19123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 191345ca1b86SEd Tanous { 191445ca1b86SEd Tanous return; 191545ca1b86SEd Tanous } 191625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19177f3e84a1SEd Tanous { 19187f3e84a1SEd Tanous // Option currently returns no systems. TBD 19197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19207f3e84a1SEd Tanous systemName); 19217f3e84a1SEd Tanous return; 19227f3e84a1SEd Tanous } 1923253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 192422d268cbSEd Tanous { 192522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 192622d268cbSEd Tanous systemName); 192722d268cbSEd Tanous return; 192822d268cbSEd Tanous } 192975710de2SXiaochao Ma std::optional<bool> resolved; 193075710de2SXiaochao Ma 193115ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 19327e860f15SJohn Edward Broadbent resolved)) 193375710de2SXiaochao Ma { 193475710de2SXiaochao Ma return; 193575710de2SXiaochao Ma } 193662598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 193775710de2SXiaochao Ma 1938e93abac6SGinu George setDbusProperty(asyncResp, "Resolved", "xyz.openbmc_project.Logging", 19399ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 19403eb66652SAsmitha Karunanithi "xyz.openbmc_project.Logging.Entry", "Resolved", 1941e93abac6SGinu George *resolved); 19427e860f15SJohn Edward Broadbent }); 194375710de2SXiaochao Ma 19447e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 194522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1946ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1947ed398213SEd Tanous 1948002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1949002d39b4SEd Tanous [&app](const crow::Request& req, 1950002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 195122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1953336e96c6SChicago Duan { 195445ca1b86SEd Tanous return; 195545ca1b86SEd Tanous } 195625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19577f3e84a1SEd Tanous { 19587f3e84a1SEd Tanous // Option currently returns no systems. TBD 19597f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19607f3e84a1SEd Tanous systemName); 19617f3e84a1SEd Tanous return; 19627f3e84a1SEd Tanous } 1963253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 196422d268cbSEd Tanous { 196522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 196622d268cbSEd Tanous systemName); 196722d268cbSEd Tanous return; 196822d268cbSEd Tanous } 196962598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 1970336e96c6SChicago Duan 19717e860f15SJohn Edward Broadbent std::string entryID = param; 1972336e96c6SChicago Duan 1973336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1974336e96c6SChicago Duan 1975336e96c6SChicago Duan // Process response from Logging service. 19765a39f77aSPatrick Williams auto respHandler = [asyncResp, 19775a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 197862598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 1979336e96c6SChicago Duan if (ec) 1980336e96c6SChicago Duan { 19813de8d8baSGeorge Liu if (ec.value() == EBADR) 19823de8d8baSGeorge Liu { 198345ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 198445ca1b86SEd Tanous entryID); 19853de8d8baSGeorge Liu return; 19863de8d8baSGeorge Liu } 1987336e96c6SChicago Duan // TODO Handle for specific error code 198862598e31SEd Tanous BMCWEB_LOG_ERROR( 198962598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 199062598e31SEd Tanous ec); 1991336e96c6SChicago Duan asyncResp->res.result( 1992336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1993336e96c6SChicago Duan return; 1994336e96c6SChicago Duan } 1995336e96c6SChicago Duan 1996336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1997336e96c6SChicago Duan }; 1998336e96c6SChicago Duan 1999336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2000336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2001336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2002336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2003336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 20047e860f15SJohn Edward Broadbent }); 2005400fd1fbSAdriana Kobylak } 2006400fd1fbSAdriana Kobylak 2007b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2008b7028ebfSSpencer Ku 2009b7028ebfSSpencer Ku inline bool 2010b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2011b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2012b7028ebfSSpencer Ku { 2013b7028ebfSSpencer Ku std::error_code ec; 2014b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2015b7028ebfSSpencer Ku if (ec) 2016b7028ebfSSpencer Ku { 2017bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2018b7028ebfSSpencer Ku return false; 2019b7028ebfSSpencer Ku } 2020b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2021b7028ebfSSpencer Ku { 2022b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2023b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2024b7028ebfSSpencer Ku // path 202511ba3979SEd Tanous if (filename.starts_with("log")) 2026b7028ebfSSpencer Ku { 2027b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2028b7028ebfSSpencer Ku } 2029b7028ebfSSpencer Ku } 2030b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2031b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2032b7028ebfSSpencer Ku // descending order. 2033b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2034b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2035b7028ebfSSpencer Ku 2036b7028ebfSSpencer Ku return true; 2037b7028ebfSSpencer Ku } 2038b7028ebfSSpencer Ku 203902cad96eSEd Tanous inline bool getHostLoggerEntries( 204002cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 204102cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2042b7028ebfSSpencer Ku { 2043b7028ebfSSpencer Ku GzFileReader logFile; 2044b7028ebfSSpencer Ku 2045b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2046b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2047b7028ebfSSpencer Ku { 2048b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2049b7028ebfSSpencer Ku { 205062598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2051b7028ebfSSpencer Ku return false; 2052b7028ebfSSpencer Ku } 2053b7028ebfSSpencer Ku } 2054b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2055b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2056b7028ebfSSpencer Ku if (!lastMessage.empty()) 2057b7028ebfSSpencer Ku { 2058b7028ebfSSpencer Ku logCount++; 2059b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2060b7028ebfSSpencer Ku { 2061b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2062b7028ebfSSpencer Ku } 2063b7028ebfSSpencer Ku } 2064b7028ebfSSpencer Ku return true; 2065b7028ebfSSpencer Ku } 2066b7028ebfSSpencer Ku 20676f056f24SEd Tanous inline void fillHostLoggerEntryJson(std::string_view logEntryID, 20686f056f24SEd Tanous std::string_view msg, 20696d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2070b7028ebfSSpencer Ku { 2071b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20729c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2073ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2074253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}", 2075253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 20766d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20776d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20786d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20796d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20806d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20816d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2082b7028ebfSSpencer Ku } 2083b7028ebfSSpencer Ku 2084b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2085b7028ebfSSpencer Ku { 208622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2087b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20881476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20891476687dSEd Tanous [&app](const crow::Request& req, 209022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 209122d268cbSEd Tanous const std::string& systemName) { 20923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 209345ca1b86SEd Tanous { 209445ca1b86SEd Tanous return; 209545ca1b86SEd Tanous } 209625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20977f3e84a1SEd Tanous { 20987f3e84a1SEd Tanous // Option currently returns no systems. TBD 20997f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21007f3e84a1SEd Tanous systemName); 21017f3e84a1SEd Tanous return; 21027f3e84a1SEd Tanous } 2103253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 210422d268cbSEd Tanous { 210522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 210622d268cbSEd Tanous systemName); 210722d268cbSEd Tanous return; 210822d268cbSEd Tanous } 2109b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2110253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 2111253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2112b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2113b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2114b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2115b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2116b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21171476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 2118253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2119253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2120b7028ebfSSpencer Ku }); 2121b7028ebfSSpencer Ku } 2122b7028ebfSSpencer Ku 2123b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2124b7028ebfSSpencer Ku { 2125b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 212622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2127b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2128002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2129002d39b4SEd Tanous [&app](const crow::Request& req, 213022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 213122d268cbSEd Tanous const std::string& systemName) { 2132c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2133c937d2bfSEd Tanous .canDelegateTop = true, 2134c937d2bfSEd Tanous .canDelegateSkip = true, 2135c937d2bfSEd Tanous }; 2136c937d2bfSEd Tanous query_param::Query delegatedQuery; 2137c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21383ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2139b7028ebfSSpencer Ku { 2140b7028ebfSSpencer Ku return; 2141b7028ebfSSpencer Ku } 214225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 21437f3e84a1SEd Tanous { 21447f3e84a1SEd Tanous // Option currently returns no systems. TBD 21457f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21467f3e84a1SEd Tanous systemName); 21477f3e84a1SEd Tanous return; 21487f3e84a1SEd Tanous } 2149253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 215022d268cbSEd Tanous { 215122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 215222d268cbSEd Tanous systemName); 215322d268cbSEd Tanous return; 215422d268cbSEd Tanous } 2155b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2156253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2157253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2158b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2159b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2160b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2161b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2162b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21630fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2164b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2165b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2166b7028ebfSSpencer Ku 2167b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2168b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2169b7028ebfSSpencer Ku { 2170bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2171b7028ebfSSpencer Ku return; 2172b7028ebfSSpencer Ku } 21733648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21743648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21755143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2176b7028ebfSSpencer Ku size_t logCount = 0; 2177b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2178b7028ebfSSpencer Ku // control by skip and top. 2179b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21803648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21813648c8beSEd Tanous logCount)) 2182b7028ebfSSpencer Ku { 2183b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2184b7028ebfSSpencer Ku return; 2185b7028ebfSSpencer Ku } 2186b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2187b7028ebfSSpencer Ku // log count 218826f6976fSEd Tanous if (logEntries.empty()) 2189b7028ebfSSpencer Ku { 2190b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2191b7028ebfSSpencer Ku return; 2192b7028ebfSSpencer Ku } 219326f6976fSEd Tanous if (!logEntries.empty()) 2194b7028ebfSSpencer Ku { 2195b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2196b7028ebfSSpencer Ku { 21976d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21983648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21993648c8beSEd Tanous hostLogEntry); 2200b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2201b7028ebfSSpencer Ku } 2202b7028ebfSSpencer Ku 2203b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 22043648c8beSEd Tanous if (skip + top < logCount) 2205b7028ebfSSpencer Ku { 2206b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 2207253f11b8SEd Tanous std::format( 2208253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=", 2209253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 22103648c8beSEd Tanous std::to_string(skip + top); 2211b7028ebfSSpencer Ku } 2212b7028ebfSSpencer Ku } 2213b7028ebfSSpencer Ku }); 2214b7028ebfSSpencer Ku } 2215b7028ebfSSpencer Ku 2216b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2217b7028ebfSSpencer Ku { 2218b7028ebfSSpencer Ku BMCWEB_ROUTE( 221922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2220b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2221b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 222245ca1b86SEd Tanous [&app](const crow::Request& req, 2223b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 222422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 222645ca1b86SEd Tanous { 222745ca1b86SEd Tanous return; 222845ca1b86SEd Tanous } 222925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 22307f3e84a1SEd Tanous { 22317f3e84a1SEd Tanous // Option currently returns no systems. TBD 22327f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22337f3e84a1SEd Tanous systemName); 22347f3e84a1SEd Tanous return; 22357f3e84a1SEd Tanous } 2236253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 223722d268cbSEd Tanous { 223822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 223922d268cbSEd Tanous systemName); 224022d268cbSEd Tanous return; 224122d268cbSEd Tanous } 22426f056f24SEd Tanous std::string_view targetID = param; 2243b7028ebfSSpencer Ku 2244b7028ebfSSpencer Ku uint64_t idInt = 0; 2245ca45aa3cSEd Tanous 22466f056f24SEd Tanous auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(), 224784396af9SPatrick Williams idInt); 22486f056f24SEd Tanous if (ec != std::errc{} || ptr != targetID.end()) 2249b7028ebfSSpencer Ku { 22509db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2251b7028ebfSSpencer Ku return; 2252b7028ebfSSpencer Ku } 2253b7028ebfSSpencer Ku 2254b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2255b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2256b7028ebfSSpencer Ku { 2257bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2258b7028ebfSSpencer Ku return; 2259b7028ebfSSpencer Ku } 2260b7028ebfSSpencer Ku 2261b7028ebfSSpencer Ku size_t logCount = 0; 22623648c8beSEd Tanous size_t top = 1; 2263b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2264b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2265b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2266b7028ebfSSpencer Ku // get that entry 2267002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2268002d39b4SEd Tanous logCount)) 2269b7028ebfSSpencer Ku { 2270b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2271b7028ebfSSpencer Ku return; 2272b7028ebfSSpencer Ku } 2273b7028ebfSSpencer Ku 2274b7028ebfSSpencer Ku if (!logEntries.empty()) 2275b7028ebfSSpencer Ku { 22766d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22776d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22786d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2279b7028ebfSSpencer Ku return; 2280b7028ebfSSpencer Ku } 2281b7028ebfSSpencer Ku 2282b7028ebfSSpencer Ku // Requested ID was not found 22839db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2284b7028ebfSSpencer Ku }); 2285b7028ebfSSpencer Ku } 2286b7028ebfSSpencer Ku 2287dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2288fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2289253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2290253f11b8SEd Tanous const std::string& managerId) 22911da66f75SEd Tanous { 22923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 229345ca1b86SEd Tanous { 229445ca1b86SEd Tanous return; 229545ca1b86SEd Tanous } 2296253f11b8SEd Tanous 2297253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2298253f11b8SEd Tanous { 2299253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2300253f11b8SEd Tanous return; 2301253f11b8SEd Tanous } 2302253f11b8SEd Tanous 23037e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 23047e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2305e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 23061da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2307253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2308253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME); 2309002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2310e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 23111da66f75SEd Tanous "Collection of LogServices for this Manager"; 2312002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2313c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2314fdd26906SClaire Weinan 231525b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_BMC_JOURNAL) 231625b54dbaSEd Tanous { 2317613dabeaSEd Tanous nlohmann::json::object_t journal; 2318253f11b8SEd Tanous journal["@odata.id"] = 2319253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal", 2320253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2321b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 232225b54dbaSEd Tanous } 2323fdd26906SClaire Weinan 2324fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2325fdd26906SClaire Weinan 232625b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 232725b54dbaSEd Tanous { 232815912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 23297a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 23307a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 23317a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 233225b54dbaSEd Tanous [asyncResp](const boost::system::error_code& ec, 233325b54dbaSEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 233425b54dbaSEd Tanous subTreePaths) { 2335fdd26906SClaire Weinan if (ec) 2336fdd26906SClaire Weinan { 233762598e31SEd Tanous BMCWEB_LOG_ERROR( 233862598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 233962598e31SEd Tanous ec); 2340fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2341fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2342fdd26906SClaire Weinan return; 2343fdd26906SClaire Weinan } 2344fdd26906SClaire Weinan 2345fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2346fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2347fdd26906SClaire Weinan 2348fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2349fdd26906SClaire Weinan { 2350fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2351fdd26906SClaire Weinan { 2352613dabeaSEd Tanous nlohmann::json::object_t member; 2353253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2354253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump", 2355253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2356b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2357fdd26906SClaire Weinan } 2358fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2359fdd26906SClaire Weinan { 2360613dabeaSEd Tanous nlohmann::json::object_t member; 2361253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2362253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/FaultLog", 2363253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2364b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2365fdd26906SClaire Weinan } 2366fdd26906SClaire Weinan } 2367fdd26906SClaire Weinan 2368e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2369fdd26906SClaire Weinan logServiceArrayLocal.size(); 23707a1dbc48SGeorge Liu }); 237125b54dbaSEd Tanous } 2372fdd26906SClaire Weinan } 2373fdd26906SClaire Weinan 2374fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2375fdd26906SClaire Weinan { 2376253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/") 2377fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2378fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2379dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2380e1f26343SJason M. Bills } 2381e1f26343SJason M. Bills 2382fdd26906SClaire Weinan inline void 2383fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2384fdd26906SClaire Weinan const std::string& dumpType) 2385c9bb6861Sraviteja-b { 2386fdd26906SClaire Weinan std::string dumpPath; 2387fdd26906SClaire Weinan std::string overWritePolicy; 2388fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2389fdd26906SClaire Weinan 2390fdd26906SClaire Weinan if (dumpType == "BMC") 239145ca1b86SEd Tanous { 2392253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump", 2393253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2394fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2395fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2396fdd26906SClaire Weinan } 2397fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2398fdd26906SClaire Weinan { 2399253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog", 2400253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2401fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2402fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2403fdd26906SClaire Weinan } 2404fdd26906SClaire Weinan else if (dumpType == "System") 2405fdd26906SClaire Weinan { 2406253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump", 2407253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2408fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2409fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2410fdd26906SClaire Weinan } 2411fdd26906SClaire Weinan else 2412fdd26906SClaire Weinan { 241362598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 241462598e31SEd Tanous dumpType); 2415fdd26906SClaire Weinan messages::internalError(asyncResp->res); 241645ca1b86SEd Tanous return; 241745ca1b86SEd Tanous } 2418fdd26906SClaire Weinan 2419fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2420fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2421c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2422fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2423fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2424fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 24257c8c4058STejas Patil 24267c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 24272b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 24280fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 24297c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 24307c8c4058STejas Patil redfishDateTimeOffset.second; 24317c8c4058STejas Patil 2432fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2433fdd26906SClaire Weinan 2434fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2435fdd26906SClaire Weinan { 2436002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 24371476687dSEd Tanous ["target"] = 2438fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2439fdd26906SClaire Weinan } 24400d946211SClaire Weinan 24410d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 24420d946211SClaire Weinan dbus::utility::getSubTreePaths( 24430d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 24440d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 24450d946211SClaire Weinan const boost::system::error_code& ec, 24460d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 24470d946211SClaire Weinan if (ec) 24480d946211SClaire Weinan { 244962598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 24500d946211SClaire Weinan // Assume that getting an error simply means there are no dump 24510d946211SClaire Weinan // LogServices. Return without adding any error response. 24520d946211SClaire Weinan return; 24530d946211SClaire Weinan } 245418f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 24550d946211SClaire Weinan for (const std::string& path : subTreePaths) 24560d946211SClaire Weinan { 24570d946211SClaire Weinan if (path == dbusDumpPath) 24580d946211SClaire Weinan { 24590d946211SClaire Weinan asyncResp->res 24600d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 24610d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 24620d946211SClaire Weinan break; 24630d946211SClaire Weinan } 24640d946211SClaire Weinan } 24650d946211SClaire Weinan }); 2466c9bb6861Sraviteja-b } 2467c9bb6861Sraviteja-b 2468fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2469fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2470253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2471253f11b8SEd Tanous const std::string& managerId) 24727e860f15SJohn Edward Broadbent { 24733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 247445ca1b86SEd Tanous { 247545ca1b86SEd Tanous return; 247645ca1b86SEd Tanous } 2477253f11b8SEd Tanous 2478253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2479253f11b8SEd Tanous { 2480253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2481253f11b8SEd Tanous return; 2482253f11b8SEd Tanous } 2483253f11b8SEd Tanous 2484fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2485fdd26906SClaire Weinan } 2486c9bb6861Sraviteja-b 248722d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 248822d268cbSEd Tanous crow::App& app, const crow::Request& req, 248922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 249022d268cbSEd Tanous const std::string& chassisId) 249122d268cbSEd Tanous { 249222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 249322d268cbSEd Tanous { 249422d268cbSEd Tanous return; 249522d268cbSEd Tanous } 2496253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 249722d268cbSEd Tanous { 249822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 249922d268cbSEd Tanous return; 250022d268cbSEd Tanous } 250122d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 250222d268cbSEd Tanous } 250322d268cbSEd Tanous 2504fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2505fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2506253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2507253f11b8SEd Tanous const std::string& managerId) 2508fdd26906SClaire Weinan { 2509fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2510fdd26906SClaire Weinan { 2511fdd26906SClaire Weinan return; 2512fdd26906SClaire Weinan } 2513253f11b8SEd Tanous 2514253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2515253f11b8SEd Tanous { 2516253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2517253f11b8SEd Tanous return; 2518253f11b8SEd Tanous } 2519fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2520fdd26906SClaire Weinan } 2521fdd26906SClaire Weinan 252222d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 252322d268cbSEd Tanous crow::App& app, const crow::Request& req, 252422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 252522d268cbSEd Tanous const std::string& chassisId) 252622d268cbSEd Tanous { 252722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 252822d268cbSEd Tanous { 252922d268cbSEd Tanous return; 253022d268cbSEd Tanous } 2531253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 253222d268cbSEd Tanous { 253322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 253422d268cbSEd Tanous return; 253522d268cbSEd Tanous } 253622d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 253722d268cbSEd Tanous } 253822d268cbSEd Tanous 2539fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2540fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2541fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2542253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2543fdd26906SClaire Weinan { 2544fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2545fdd26906SClaire Weinan { 2546fdd26906SClaire Weinan return; 2547fdd26906SClaire Weinan } 2548253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2549253f11b8SEd Tanous { 2550253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2551253f11b8SEd Tanous return; 2552253f11b8SEd Tanous } 2553fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2554fdd26906SClaire Weinan } 2555168d1b1aSCarson Labrado 255622d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 255722d268cbSEd Tanous crow::App& app, const crow::Request& req, 255822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 255922d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 256022d268cbSEd Tanous { 256122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 256222d268cbSEd Tanous { 256322d268cbSEd Tanous return; 256422d268cbSEd Tanous } 2565253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 256622d268cbSEd Tanous { 256722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 256822d268cbSEd Tanous return; 256922d268cbSEd Tanous } 257022d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 257122d268cbSEd Tanous } 2572fdd26906SClaire Weinan 2573fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2574fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2575fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2576253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2577fdd26906SClaire Weinan { 2578fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2579fdd26906SClaire Weinan { 2580fdd26906SClaire Weinan return; 2581fdd26906SClaire Weinan } 2582253f11b8SEd Tanous 2583253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2584253f11b8SEd Tanous { 2585253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2586253f11b8SEd Tanous return; 2587253f11b8SEd Tanous } 2588fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2589fdd26906SClaire Weinan } 2590fdd26906SClaire Weinan 259122d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 259222d268cbSEd Tanous crow::App& app, const crow::Request& req, 259322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 259422d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 259522d268cbSEd Tanous { 259622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 259722d268cbSEd Tanous { 259822d268cbSEd Tanous return; 259922d268cbSEd Tanous } 2600253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 260122d268cbSEd Tanous { 260222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 260322d268cbSEd Tanous return; 260422d268cbSEd Tanous } 260522d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 260622d268cbSEd Tanous } 260722d268cbSEd Tanous 2608168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2609168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2610168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2611253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2612168d1b1aSCarson Labrado { 2613168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2614168d1b1aSCarson Labrado { 2615168d1b1aSCarson Labrado return; 2616168d1b1aSCarson Labrado } 2617253f11b8SEd Tanous 2618253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2619253f11b8SEd Tanous { 2620253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2621253f11b8SEd Tanous return; 2622253f11b8SEd Tanous } 2623168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2624168d1b1aSCarson Labrado } 2625168d1b1aSCarson Labrado 2626168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2627168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2628168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2629168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2630168d1b1aSCarson Labrado { 2631168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2632168d1b1aSCarson Labrado { 2633168d1b1aSCarson Labrado return; 2634168d1b1aSCarson Labrado } 2635168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2636168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2637168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2638168d1b1aSCarson Labrado { 2639168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2640168d1b1aSCarson Labrado return; 2641168d1b1aSCarson Labrado } 2642168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2643168d1b1aSCarson Labrado } 2644168d1b1aSCarson Labrado 2645fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2646fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2647253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2648253f11b8SEd Tanous const std::string& managerId) 2649fdd26906SClaire Weinan { 2650fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2651fdd26906SClaire Weinan { 2652fdd26906SClaire Weinan return; 2653fdd26906SClaire Weinan } 2654253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2655253f11b8SEd Tanous { 2656253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2657253f11b8SEd Tanous return; 2658253f11b8SEd Tanous } 2659253f11b8SEd Tanous 2660fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2661fdd26906SClaire Weinan } 2662fdd26906SClaire Weinan 266322d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 266422d268cbSEd Tanous crow::App& app, const crow::Request& req, 266522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26667f3e84a1SEd Tanous const std::string& systemName) 266722d268cbSEd Tanous { 266822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 266922d268cbSEd Tanous { 267022d268cbSEd Tanous return; 267122d268cbSEd Tanous } 26727f3e84a1SEd Tanous 267325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 267422d268cbSEd Tanous { 26757f3e84a1SEd Tanous // Option currently returns no systems. TBD 26767f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26777f3e84a1SEd Tanous systemName); 26787f3e84a1SEd Tanous return; 26797f3e84a1SEd Tanous } 2680253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 26817f3e84a1SEd Tanous { 26827f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26837f3e84a1SEd Tanous systemName); 268422d268cbSEd Tanous return; 268522d268cbSEd Tanous } 268622d268cbSEd Tanous createDump(asyncResp, req, "System"); 268722d268cbSEd Tanous } 268822d268cbSEd Tanous 2689fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2690fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2691253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2692253f11b8SEd Tanous const std::string& managerId) 2693fdd26906SClaire Weinan { 2694fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2695fdd26906SClaire Weinan { 2696fdd26906SClaire Weinan return; 2697fdd26906SClaire Weinan } 2698253f11b8SEd Tanous 2699253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2700253f11b8SEd Tanous { 2701253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2702253f11b8SEd Tanous return; 2703253f11b8SEd Tanous } 2704fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2705fdd26906SClaire Weinan } 2706fdd26906SClaire Weinan 270722d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 270822d268cbSEd Tanous crow::App& app, const crow::Request& req, 270922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27107f3e84a1SEd Tanous const std::string& systemName) 271122d268cbSEd Tanous { 271222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 271322d268cbSEd Tanous { 271422d268cbSEd Tanous return; 271522d268cbSEd Tanous } 271625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 271722d268cbSEd Tanous { 27187f3e84a1SEd Tanous // Option currently returns no systems. TBD 27197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27207f3e84a1SEd Tanous systemName); 27217f3e84a1SEd Tanous return; 27227f3e84a1SEd Tanous } 2723253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 27247f3e84a1SEd Tanous { 27257f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27267f3e84a1SEd Tanous systemName); 272722d268cbSEd Tanous return; 272822d268cbSEd Tanous } 272922d268cbSEd Tanous clearDump(asyncResp, "System"); 273022d268cbSEd Tanous } 273122d268cbSEd Tanous 2732fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2733fdd26906SClaire Weinan { 2734253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/") 2735fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2736fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2737fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2738fdd26906SClaire Weinan } 2739fdd26906SClaire Weinan 2740fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2741fdd26906SClaire Weinan { 2742253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/") 2743fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2744fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2745fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2746c9bb6861Sraviteja-b } 2747c9bb6861Sraviteja-b 27487e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2749c9bb6861Sraviteja-b { 27507e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2751253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2752ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2753fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2754fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2755fdd26906SClaire Weinan 27567e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2757253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2758ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2759fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2760fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2761c9bb6861Sraviteja-b } 2762c9bb6861Sraviteja-b 2763168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 2764168d1b1aSCarson Labrado { 2765168d1b1aSCarson Labrado BMCWEB_ROUTE( 2766168d1b1aSCarson Labrado app, 2767253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/") 2768168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2769168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2770168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 2771168d1b1aSCarson Labrado } 2772168d1b1aSCarson Labrado 27737e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2774c9bb6861Sraviteja-b { 27750fda0f12SGeorge Liu BMCWEB_ROUTE( 27760fda0f12SGeorge Liu app, 2777253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2778ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 27797e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2780fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2781fdd26906SClaire Weinan std::ref(app), "BMC")); 2782a43be80fSAsmitha Karunanithi } 2783a43be80fSAsmitha Karunanithi 27847e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 278580319af1SAsmitha Karunanithi { 27860fda0f12SGeorge Liu BMCWEB_ROUTE( 27870fda0f12SGeorge Liu app, 2788253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2789ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2790fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2791fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 279245ca1b86SEd Tanous } 2793fdd26906SClaire Weinan 2794168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 2795168d1b1aSCarson Labrado { 2796168d1b1aSCarson Labrado BMCWEB_ROUTE( 2797168d1b1aSCarson Labrado app, 27989e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 2799168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2800168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2801168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 2802168d1b1aSCarson Labrado } 2803168d1b1aSCarson Labrado 2804fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2805fdd26906SClaire Weinan { 2806253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/") 2807fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2808fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2809fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2810fdd26906SClaire Weinan } 2811fdd26906SClaire Weinan 2812fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2813fdd26906SClaire Weinan { 2814253f11b8SEd Tanous BMCWEB_ROUTE(app, 2815253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/") 2816fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2817fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2818fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2819fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2820fdd26906SClaire Weinan } 2821fdd26906SClaire Weinan 2822fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2823fdd26906SClaire Weinan { 2824253f11b8SEd Tanous BMCWEB_ROUTE( 2825253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2826fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2827fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2828fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2829fdd26906SClaire Weinan 2830253f11b8SEd Tanous BMCWEB_ROUTE( 2831253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2832fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2833fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2834fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2835fdd26906SClaire Weinan } 2836fdd26906SClaire Weinan 2837fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2838fdd26906SClaire Weinan { 2839fdd26906SClaire Weinan BMCWEB_ROUTE( 2840fdd26906SClaire Weinan app, 2841253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/") 2842fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2843fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2844fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 28455cb1dd27SAsmitha Karunanithi } 28465cb1dd27SAsmitha Karunanithi 28477e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 28485cb1dd27SAsmitha Karunanithi { 284922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2850ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 28516ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 285222d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 28535cb1dd27SAsmitha Karunanithi } 28545cb1dd27SAsmitha Karunanithi 28557e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 28567e860f15SJohn Edward Broadbent { 285722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2858ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 285922d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 286022d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 286122d268cbSEd Tanous std::ref(app))); 28625cb1dd27SAsmitha Karunanithi } 28635cb1dd27SAsmitha Karunanithi 28647e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 28655cb1dd27SAsmitha Karunanithi { 28667e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 286722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2868ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 28696ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 287022d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 28718d1b46d7Szhanghch05 28727e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 287322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2874ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 28756ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 287622d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 28775cb1dd27SAsmitha Karunanithi } 2878c9bb6861Sraviteja-b 28797e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2880c9bb6861Sraviteja-b { 28810fda0f12SGeorge Liu BMCWEB_ROUTE( 28820fda0f12SGeorge Liu app, 288322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2884ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 288522d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 288622d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 288722d268cbSEd Tanous std::ref(app))); 2888a43be80fSAsmitha Karunanithi } 2889a43be80fSAsmitha Karunanithi 28907e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2891a43be80fSAsmitha Karunanithi { 28920fda0f12SGeorge Liu BMCWEB_ROUTE( 28930fda0f12SGeorge Liu app, 289422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2895ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28966ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 289722d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2898013487e5Sraviteja-b } 2899013487e5Sraviteja-b 29007e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29011da66f75SEd Tanous { 29023946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29033946028dSAppaRao Puli // method for security reasons. 29041da66f75SEd Tanous /** 29051da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29061da66f75SEd Tanous */ 290722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2908ed398213SEd Tanous // This is incorrect, should be: 2909ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2910432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2911002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2912002d39b4SEd Tanous [&app](const crow::Request& req, 291322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 291422d268cbSEd Tanous const std::string& systemName) { 29153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 291645ca1b86SEd Tanous { 291745ca1b86SEd Tanous return; 291845ca1b86SEd Tanous } 291925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 29207f3e84a1SEd Tanous { 29217f3e84a1SEd Tanous // Option currently returns no systems. TBD 29227f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29237f3e84a1SEd Tanous systemName); 29247f3e84a1SEd Tanous return; 29257f3e84a1SEd Tanous } 2926253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 292722d268cbSEd Tanous { 292822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 292922d268cbSEd Tanous systemName); 293022d268cbSEd Tanous return; 293122d268cbSEd Tanous } 293222d268cbSEd Tanous 29337e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29347e860f15SJohn Edward Broadbent // SubRoute 29350f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2936253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 2937253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2938e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 29398e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 29404f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 29414f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 294215b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 2943e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 2944e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 29457c8c4058STejas Patil 29467c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 29472b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 29487c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 29497c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 29507c8c4058STejas Patil redfishDateTimeOffset.second; 29517c8c4058STejas Patil 29521476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 2953253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 2954253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2955253f11b8SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 2956253f11b8SEd Tanous ["target"] = std::format( 2957253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog", 2958253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2959002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 2960253f11b8SEd Tanous ["target"] = std::format( 2961253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData", 2962253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 29637e860f15SJohn Edward Broadbent }); 29641da66f75SEd Tanous } 29651da66f75SEd Tanous 29667e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 29675b61b5e8SJason M. Bills { 29680fda0f12SGeorge Liu BMCWEB_ROUTE( 29690fda0f12SGeorge Liu app, 297022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 2971ed398213SEd Tanous // This is incorrect, should be: 2972ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 2973432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 29747e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 297545ca1b86SEd Tanous [&app](const crow::Request& req, 297622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297722d268cbSEd Tanous const std::string& systemName) { 29783ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 297945ca1b86SEd Tanous { 298045ca1b86SEd Tanous return; 298145ca1b86SEd Tanous } 298225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 29837f3e84a1SEd Tanous { 29847f3e84a1SEd Tanous // Option currently returns no systems. TBD 29857f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29867f3e84a1SEd Tanous systemName); 29877f3e84a1SEd Tanous return; 29887f3e84a1SEd Tanous } 2989253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 299022d268cbSEd Tanous { 299122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 299222d268cbSEd Tanous systemName); 299322d268cbSEd Tanous return; 299422d268cbSEd Tanous } 29955b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 29965e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 2997cb13a392SEd Tanous const std::string&) { 29985b61b5e8SJason M. Bills if (ec) 29995b61b5e8SJason M. Bills { 30005b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30015b61b5e8SJason M. Bills return; 30025b61b5e8SJason M. Bills } 30035b61b5e8SJason M. Bills messages::success(asyncResp->res); 30045b61b5e8SJason M. Bills }, 3005002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30067e860f15SJohn Edward Broadbent }); 30075b61b5e8SJason M. Bills } 30085b61b5e8SJason M. Bills 30098d1b46d7Szhanghch05 static void 30108d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30118d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3012e855dd28SJason M. Bills { 3013043a0536SJohnathan Mantey auto getStoredLogCallback = 3014b9d36b47SEd Tanous [asyncResp, logID, 30155e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3016b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3017e855dd28SJason M. Bills if (ec) 3018e855dd28SJason M. Bills { 301962598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 30201ddcf01aSJason M. Bills if (ec.value() == 30211ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30221ddcf01aSJason M. Bills { 3023002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30241ddcf01aSJason M. Bills } 30251ddcf01aSJason M. Bills else 30261ddcf01aSJason M. Bills { 3027e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30281ddcf01aSJason M. Bills } 3029e855dd28SJason M. Bills return; 3030e855dd28SJason M. Bills } 3031043a0536SJohnathan Mantey 3032043a0536SJohnathan Mantey std::string timestamp{}; 3033043a0536SJohnathan Mantey std::string filename{}; 3034043a0536SJohnathan Mantey std::string logfile{}; 30352c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3036043a0536SJohnathan Mantey 3037043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3038e855dd28SJason M. Bills { 30399db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3040e855dd28SJason M. Bills return; 3041e855dd28SJason M. Bills } 3042e855dd28SJason M. Bills 3043043a0536SJohnathan Mantey std::string crashdumpURI = 3044253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/", 3045253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3046043a0536SJohnathan Mantey logID + "/" + filename; 304784afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30489c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3049ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3050253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}", 3051253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logID); 305284afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 305384afc48bSJason M. Bills logEntry["Id"] = logID; 305484afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 305584afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 305684afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 305784afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 305884afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 30592b20ef6eSJason M. Bills 30602b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 30612b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 30622b20ef6eSJason M. Bills // directly 30632b20ef6eSJason M. Bills if (logEntryJson.is_array()) 30642b20ef6eSJason M. Bills { 30652b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 30662b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 30672b20ef6eSJason M. Bills logEntryJson.size(); 30682b20ef6eSJason M. Bills } 30692b20ef6eSJason M. Bills else 30702b20ef6eSJason M. Bills { 3071d405bb51SJason M. Bills logEntryJson.update(logEntry); 30722b20ef6eSJason M. Bills } 3073e855dd28SJason M. Bills }; 3074d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3075d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3076d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3077d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3078e855dd28SJason M. Bills } 3079e855dd28SJason M. Bills 30807e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 30811da66f75SEd Tanous { 30823946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30833946028dSAppaRao Puli // method for security reasons. 30841da66f75SEd Tanous /** 30851da66f75SEd Tanous * Functions triggers appropriate requests on DBus 30861da66f75SEd Tanous */ 30877e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 308822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3089ed398213SEd Tanous // This is incorrect, should be. 3090ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3091432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3092002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3093002d39b4SEd Tanous [&app](const crow::Request& req, 309422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 309522d268cbSEd Tanous const std::string& systemName) { 30963ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 309745ca1b86SEd Tanous { 309845ca1b86SEd Tanous return; 309945ca1b86SEd Tanous } 310025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 31017f3e84a1SEd Tanous { 31027f3e84a1SEd Tanous // Option currently returns no systems. TBD 31037f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31047f3e84a1SEd Tanous systemName); 31057f3e84a1SEd Tanous return; 31067f3e84a1SEd Tanous } 3107253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 310822d268cbSEd Tanous { 310922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 311022d268cbSEd Tanous systemName); 311122d268cbSEd Tanous return; 311222d268cbSEd Tanous } 311322d268cbSEd Tanous 31147a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 31157a1dbc48SGeorge Liu crashdumpInterface}; 31167a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 31177a1dbc48SGeorge Liu "/", 0, interfaces, 31187a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 31192b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31201da66f75SEd Tanous if (ec) 31211da66f75SEd Tanous { 31221da66f75SEd Tanous if (ec.value() != 31231da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31241da66f75SEd Tanous { 312562598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 312662598e31SEd Tanous ec.message()); 3127f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31281da66f75SEd Tanous return; 31291da66f75SEd Tanous } 31301da66f75SEd Tanous } 3131e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31321da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 3133253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 3134253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 3135253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3136002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3137e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3138424c4176SJason M. Bills "Collection of Crashdump Entries"; 3139002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3140a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31412b20ef6eSJason M. Bills 31422b20ef6eSJason M. Bills for (const std::string& path : resp) 31431da66f75SEd Tanous { 31442b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3145e855dd28SJason M. Bills // Get the log ID 31462b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31472b20ef6eSJason M. Bills if (logID.empty()) 31481da66f75SEd Tanous { 3149e855dd28SJason M. Bills continue; 31501da66f75SEd Tanous } 3151e855dd28SJason M. Bills // Add the log entry to the array 31522b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31532b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31541da66f75SEd Tanous } 31557a1dbc48SGeorge Liu }); 31567e860f15SJohn Edward Broadbent }); 31571da66f75SEd Tanous } 31581da66f75SEd Tanous 31597e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31601da66f75SEd Tanous { 31613946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31623946028dSAppaRao Puli // method for security reasons. 31631da66f75SEd Tanous 31647e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 316522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3166ed398213SEd Tanous // this is incorrect, should be 3167ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3168432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 31697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 317045ca1b86SEd Tanous [&app](const crow::Request& req, 31717e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 317222d268cbSEd Tanous const std::string& systemName, const std::string& param) { 31733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 317445ca1b86SEd Tanous { 317545ca1b86SEd Tanous return; 317645ca1b86SEd Tanous } 317725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 31787f3e84a1SEd Tanous { 31797f3e84a1SEd Tanous // Option currently returns no systems. TBD 31807f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31817f3e84a1SEd Tanous systemName); 31827f3e84a1SEd Tanous return; 31837f3e84a1SEd Tanous } 3184253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 318522d268cbSEd Tanous { 318622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 318722d268cbSEd Tanous systemName); 318822d268cbSEd Tanous return; 318922d268cbSEd Tanous } 31907e860f15SJohn Edward Broadbent const std::string& logID = param; 3191e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 31927e860f15SJohn Edward Broadbent }); 3193e855dd28SJason M. Bills } 3194e855dd28SJason M. Bills 31957e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3196e855dd28SJason M. Bills { 31973946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31983946028dSAppaRao Puli // method for security reasons. 31997e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32007e860f15SJohn Edward Broadbent app, 320122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3202ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3204a4ce114aSNan Zhou [](const crow::Request& req, 32057e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 320622d268cbSEd Tanous const std::string& systemName, const std::string& logID, 320722d268cbSEd Tanous const std::string& fileName) { 32082a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32092a9beeedSShounak Mitra // Redfish resource. 321022d268cbSEd Tanous 321125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 32127f3e84a1SEd Tanous { 32137f3e84a1SEd Tanous // Option currently returns no systems. TBD 32147f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32157f3e84a1SEd Tanous systemName); 32167f3e84a1SEd Tanous return; 32177f3e84a1SEd Tanous } 3218253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 321922d268cbSEd Tanous { 322022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 322122d268cbSEd Tanous systemName); 322222d268cbSEd Tanous return; 322322d268cbSEd Tanous } 322422d268cbSEd Tanous 3225043a0536SJohnathan Mantey auto getStoredLogCallback = 322639662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 32275e7e2dc5SEd Tanous const boost::system::error_code& ec, 3228002d39b4SEd Tanous const std::vector< 3229002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32307e860f15SJohn Edward Broadbent resp) { 32311da66f75SEd Tanous if (ec) 32321da66f75SEd Tanous { 323362598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3234f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32351da66f75SEd Tanous return; 32361da66f75SEd Tanous } 3237e855dd28SJason M. Bills 3238043a0536SJohnathan Mantey std::string dbusFilename{}; 3239043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3240043a0536SJohnathan Mantey std::string dbusFilepath{}; 3241043a0536SJohnathan Mantey 3242002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3243002d39b4SEd Tanous dbusFilepath); 3244043a0536SJohnathan Mantey 3245043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3246043a0536SJohnathan Mantey dbusFilepath.empty()) 32471da66f75SEd Tanous { 32489db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32491da66f75SEd Tanous return; 32501da66f75SEd Tanous } 3251e855dd28SJason M. Bills 3252043a0536SJohnathan Mantey // Verify the file name parameter is correct 3253043a0536SJohnathan Mantey if (fileName != dbusFilename) 3254043a0536SJohnathan Mantey { 32559db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3256043a0536SJohnathan Mantey return; 3257043a0536SJohnathan Mantey } 3258043a0536SJohnathan Mantey 325927b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3260043a0536SJohnathan Mantey { 32619db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3262043a0536SJohnathan Mantey return; 3263043a0536SJohnathan Mantey } 3264043a0536SJohnathan Mantey 32657e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32667e860f15SJohn Edward Broadbent // from a browser 3267d9f6c621SEd Tanous asyncResp->res.addHeader( 3268d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 32691da66f75SEd Tanous }; 3270d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3271d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3272d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3273d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 32747e860f15SJohn Edward Broadbent }); 32751da66f75SEd Tanous } 32761da66f75SEd Tanous 3277c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3278c5a4c82aSJason M. Bills { 3279c5a4c82aSJason M. Bills onDemand, 3280c5a4c82aSJason M. Bills telemetry, 3281c5a4c82aSJason M. Bills invalid, 3282c5a4c82aSJason M. Bills }; 3283c5a4c82aSJason M. Bills 328426ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3285c5a4c82aSJason M. Bills { 3286c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3287c5a4c82aSJason M. Bills { 3288c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3289c5a4c82aSJason M. Bills } 3290c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3291c5a4c82aSJason M. Bills { 3292c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3293c5a4c82aSJason M. Bills } 3294c5a4c82aSJason M. Bills 3295c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3296c5a4c82aSJason M. Bills } 3297c5a4c82aSJason M. Bills 32987e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 32991da66f75SEd Tanous { 33003946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33013946028dSAppaRao Puli // method for security reasons. 33020fda0f12SGeorge Liu BMCWEB_ROUTE( 33030fda0f12SGeorge Liu app, 330422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3305ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3306ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3307432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3308002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3309002d39b4SEd Tanous [&app](const crow::Request& req, 331022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 331122d268cbSEd Tanous const std::string& systemName) { 33123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 331345ca1b86SEd Tanous { 331445ca1b86SEd Tanous return; 331545ca1b86SEd Tanous } 331622d268cbSEd Tanous 331725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 33187f3e84a1SEd Tanous { 33197f3e84a1SEd Tanous // Option currently returns no systems. TBD 33207f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33217f3e84a1SEd Tanous systemName); 33227f3e84a1SEd Tanous return; 33237f3e84a1SEd Tanous } 3324253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 332522d268cbSEd Tanous { 332622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 332722d268cbSEd Tanous systemName); 332822d268cbSEd Tanous return; 332922d268cbSEd Tanous } 333022d268cbSEd Tanous 33318e6c099aSJason M. Bills std::string diagnosticDataType; 33328e6c099aSJason M. Bills std::string oemDiagnosticDataType; 333315ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3334002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3335002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33368e6c099aSJason M. Bills { 33378e6c099aSJason M. Bills return; 33388e6c099aSJason M. Bills } 33398e6c099aSJason M. Bills 33408e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33418e6c099aSJason M. Bills { 334262598e31SEd Tanous BMCWEB_LOG_ERROR( 334362598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 33448e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33458e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33468e6c099aSJason M. Bills "CollectDiagnosticData"); 33478e6c099aSJason M. Bills return; 33488e6c099aSJason M. Bills } 33498e6c099aSJason M. Bills 3350c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3351c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3352c5a4c82aSJason M. Bills 3353c5a4c82aSJason M. Bills std::string iface; 3354c5a4c82aSJason M. Bills std::string method; 3355c5a4c82aSJason M. Bills std::string taskMatchStr; 3356c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3357c5a4c82aSJason M. Bills { 3358c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3359c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3360c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3361c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3362c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3363c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3364c5a4c82aSJason M. Bills } 3365c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3366c5a4c82aSJason M. Bills { 3367c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3368c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3369c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3370c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3371c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3372c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3373c5a4c82aSJason M. Bills } 3374c5a4c82aSJason M. Bills else 3375c5a4c82aSJason M. Bills { 337662598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 337762598e31SEd Tanous oemDiagnosticDataType); 3378c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3379002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3380002d39b4SEd Tanous "CollectDiagnosticData"); 3381c5a4c82aSJason M. Bills return; 3382c5a4c82aSJason M. Bills } 3383c5a4c82aSJason M. Bills 3384c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3385c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 33865e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 338798be3e39SEd Tanous const std::string&) mutable { 33881da66f75SEd Tanous if (ec) 33891da66f75SEd Tanous { 3390002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 33911da66f75SEd Tanous { 3392f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 33931da66f75SEd Tanous } 33944363d3b2SJason M. Bills else if (ec.value() == 33954363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 33964363d3b2SJason M. Bills { 3397002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3398002d39b4SEd Tanous "60"); 33994363d3b2SJason M. Bills } 34001da66f75SEd Tanous else 34011da66f75SEd Tanous { 3402f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34031da66f75SEd Tanous } 34041da66f75SEd Tanous return; 34051da66f75SEd Tanous } 3406002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 34078b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3408002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 34098b24275dSEd Tanous if (!ec2) 341066afe4faSJames Feist { 3411002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3412e5d5006bSJames Feist std::to_string(taskData->index))); 3413831d6b09SJames Feist taskData->state = "Completed"; 341466afe4faSJames Feist } 341532898ceaSJames Feist return task::completed; 341666afe4faSJames Feist }, 3417c5a4c82aSJason M. Bills taskMatchStr); 3418c5a4c82aSJason M. Bills 341946229577SJames Feist task->startTimer(std::chrono::minutes(5)); 342046229577SJames Feist task->populateResp(asyncResp->res); 342198be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34221da66f75SEd Tanous }; 34238e6c099aSJason M. Bills 34241da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3425002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3426002d39b4SEd Tanous iface, method); 34277e860f15SJohn Edward Broadbent }); 34286eda7685SKenny L. Ku } 34296eda7685SKenny L. Ku 3430cb92c03bSAndrew Geissler /** 3431cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3432cb92c03bSAndrew Geissler */ 34337e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3434cb92c03bSAndrew Geissler { 3435cb92c03bSAndrew Geissler /** 3436cb92c03bSAndrew Geissler * Function handles POST method request. 3437cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3438cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3439cb92c03bSAndrew Geissler */ 34407e860f15SJohn Edward Broadbent 34410fda0f12SGeorge Liu BMCWEB_ROUTE( 34420fda0f12SGeorge Liu app, 344322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3444ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34457e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 344645ca1b86SEd Tanous [&app](const crow::Request& req, 344722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 344822d268cbSEd Tanous const std::string& systemName) { 34493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 345045ca1b86SEd Tanous { 345145ca1b86SEd Tanous return; 345245ca1b86SEd Tanous } 345325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 34547f3e84a1SEd Tanous { 34557f3e84a1SEd Tanous // Option currently returns no systems. TBD 34567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34577f3e84a1SEd Tanous systemName); 34587f3e84a1SEd Tanous return; 34597f3e84a1SEd Tanous } 3460253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 346122d268cbSEd Tanous { 346222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 346322d268cbSEd Tanous systemName); 346422d268cbSEd Tanous return; 346522d268cbSEd Tanous } 346662598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3467cb92c03bSAndrew Geissler 3468cb92c03bSAndrew Geissler // Process response from Logging service. 34695e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 347062598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3471cb92c03bSAndrew Geissler if (ec) 3472cb92c03bSAndrew Geissler { 3473cb92c03bSAndrew Geissler // TODO Handle for specific error code 347462598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3475cb92c03bSAndrew Geissler asyncResp->res.result( 3476cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3477cb92c03bSAndrew Geissler return; 3478cb92c03bSAndrew Geissler } 3479cb92c03bSAndrew Geissler 3480002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3481cb92c03bSAndrew Geissler }; 3482cb92c03bSAndrew Geissler 3483cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3484cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 34852c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3486cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3487cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 34887e860f15SJohn Edward Broadbent }); 3489cb92c03bSAndrew Geissler } 3490a3316fc6SZhikuiRen 3491a3316fc6SZhikuiRen /**************************************************** 3492a3316fc6SZhikuiRen * Redfish PostCode interfaces 3493a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3494a3316fc6SZhikuiRen ******************************************************/ 34957e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3496a3316fc6SZhikuiRen { 349722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3498ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3499002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3500002d39b4SEd Tanous [&app](const crow::Request& req, 350122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350222d268cbSEd Tanous const std::string& systemName) { 35033ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 350445ca1b86SEd Tanous { 350545ca1b86SEd Tanous return; 350645ca1b86SEd Tanous } 350725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35087f3e84a1SEd Tanous { 35097f3e84a1SEd Tanous // Option currently returns no systems. TBD 35107f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35117f3e84a1SEd Tanous systemName); 35127f3e84a1SEd Tanous return; 35137f3e84a1SEd Tanous } 3514253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 351522d268cbSEd Tanous { 351622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 351722d268cbSEd Tanous systemName); 351822d268cbSEd Tanous return; 351922d268cbSEd Tanous } 35201476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3521253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 3522253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35231476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3524b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 35251476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35261476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3527ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 35281476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35291476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3530253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3531253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35327c8c4058STejas Patil 35337c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35342b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35350fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35367c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35377c8c4058STejas Patil redfishDateTimeOffset.second; 35387c8c4058STejas Patil 353920fa6a2cSEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 354020fa6a2cSEd Tanous ["target"] = std::format( 3541253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 354220fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35437e860f15SJohn Edward Broadbent }); 3544a3316fc6SZhikuiRen } 3545a3316fc6SZhikuiRen 35467e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3547a3316fc6SZhikuiRen { 35480fda0f12SGeorge Liu BMCWEB_ROUTE( 35490fda0f12SGeorge Liu app, 355022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3551ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3552ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3553432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35547e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 355545ca1b86SEd Tanous [&app](const crow::Request& req, 355622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 355722d268cbSEd Tanous const std::string& systemName) { 35583ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 355945ca1b86SEd Tanous { 356045ca1b86SEd Tanous return; 356145ca1b86SEd Tanous } 356225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35637f3e84a1SEd Tanous { 35647f3e84a1SEd Tanous // Option currently returns no systems. TBD 35657f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35667f3e84a1SEd Tanous systemName); 35677f3e84a1SEd Tanous return; 35687f3e84a1SEd Tanous } 3569253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 357022d268cbSEd Tanous { 357122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 357222d268cbSEd Tanous systemName); 357322d268cbSEd Tanous return; 357422d268cbSEd Tanous } 357562598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3576a3316fc6SZhikuiRen 3577a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3578a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 35795e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3580a3316fc6SZhikuiRen if (ec) 3581a3316fc6SZhikuiRen { 3582a3316fc6SZhikuiRen // TODO Handle for specific error code 358362598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 358462598e31SEd Tanous ec); 3585002d39b4SEd Tanous asyncResp->res.result( 3586002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3587a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3588a3316fc6SZhikuiRen return; 3589a3316fc6SZhikuiRen } 359018fc70c0STony Lee messages::success(asyncResp->res); 3591a3316fc6SZhikuiRen }, 359215124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 359315124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3594a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35957e860f15SJohn Edward Broadbent }); 3596a3316fc6SZhikuiRen } 3597a3316fc6SZhikuiRen 35986f284d24SJiaqing Zhao /** 35996f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 36006f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 36016f284d24SJiaqing Zhao * 36026f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 36036f284d24SJiaqing Zhao * @param[out] currentValue Current value 36046f284d24SJiaqing Zhao * @param[out] index Index value 36056f284d24SJiaqing Zhao * 36066f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 36076f284d24SJiaqing Zhao */ 36086f056f24SEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 3609df254f2cSEd Tanous uint16_t& index) 36106f284d24SJiaqing Zhao { 36116f284d24SJiaqing Zhao std::vector<std::string> split; 361250ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 36136f056f24SEd Tanous if (split.size() != 2) 36146f056f24SEd Tanous { 36156f056f24SEd Tanous return false; 36166f056f24SEd Tanous } 36176f056f24SEd Tanous std::string_view postCodeNumber = split[0]; 36186f056f24SEd Tanous if (postCodeNumber.size() < 2) 36196f056f24SEd Tanous { 36206f056f24SEd Tanous return false; 36216f056f24SEd Tanous } 36226f056f24SEd Tanous if (postCodeNumber[0] != 'B') 36236f056f24SEd Tanous { 36246f056f24SEd Tanous return false; 36256f056f24SEd Tanous } 36266f056f24SEd Tanous postCodeNumber.remove_prefix(1); 36276f056f24SEd Tanous auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(), 36286f056f24SEd Tanous postCodeNumber.end(), index); 36296f056f24SEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 36306f284d24SJiaqing Zhao { 36316f284d24SJiaqing Zhao return false; 36326f284d24SJiaqing Zhao } 36336f284d24SJiaqing Zhao 36346f056f24SEd Tanous std::string_view postCodeIndex = split[1]; 36356f284d24SJiaqing Zhao 36366f056f24SEd Tanous auto [ptrValue, ecValue] = std::from_chars( 36376f056f24SEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 36386f284d24SJiaqing Zhao 36396f056f24SEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 36406f284d24SJiaqing Zhao } 36416f284d24SJiaqing Zhao 36426f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3643ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36446c9a279eSManojkiran Eda const boost::container::flat_map< 36456c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3646a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3647a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3648a3316fc6SZhikuiRen { 3649a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3650fffb8c1fSEd Tanous const registries::Message* message = 3651fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3652dc8cfa66SEd Tanous if (message == nullptr) 3653dc8cfa66SEd Tanous { 3654dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 3655dc8cfa66SEd Tanous return false; 3656dc8cfa66SEd Tanous } 3657a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3658a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 36596c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36606c9a279eSManojkiran Eda code : postcode) 3661a3316fc6SZhikuiRen { 3662a3316fc6SZhikuiRen currentCodeIndex++; 3663a3316fc6SZhikuiRen std::string postcodeEntryID = 3664a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3665a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3666a3316fc6SZhikuiRen 3667a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3668a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3669a3316fc6SZhikuiRen 3670a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3671a3316fc6SZhikuiRen { // already incremented 3672a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3673a3316fc6SZhikuiRen } 3674a3316fc6SZhikuiRen else 3675a3316fc6SZhikuiRen { 3676a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3677a3316fc6SZhikuiRen } 3678a3316fc6SZhikuiRen 3679a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3680a3316fc6SZhikuiRen // not fall between top and skip 3681a3316fc6SZhikuiRen if ((codeIndex == 0) && 3682a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3683a3316fc6SZhikuiRen { 3684a3316fc6SZhikuiRen continue; 3685a3316fc6SZhikuiRen } 3686a3316fc6SZhikuiRen 36874e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3688a3316fc6SZhikuiRen // currentIndex 3689a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3690a3316fc6SZhikuiRen { 3691a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3692a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3693a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3694a3316fc6SZhikuiRen continue; 3695a3316fc6SZhikuiRen } 3696a3316fc6SZhikuiRen 3697a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3698a3316fc6SZhikuiRen // index 3699a3316fc6SZhikuiRen 3700a3316fc6SZhikuiRen // Get the Created time from the timestamp 3701a3316fc6SZhikuiRen std::string entryTimeStr; 37022a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3703a3316fc6SZhikuiRen 3704a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3705a3316fc6SZhikuiRen std::ostringstream hexCode; 3706a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 37076c9a279eSManojkiran Eda << std::get<0>(code.second); 3708a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3709a3316fc6SZhikuiRen // Set Fixed -Point Notation 3710a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3711a3316fc6SZhikuiRen // Set precision to 4 digits 3712a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3713a3316fc6SZhikuiRen // Add double to stream 3714a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3715a3316fc6SZhikuiRen 37161e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 37171e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 37181e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3719a3316fc6SZhikuiRen 37201e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 37211e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 37221e6deaf6SEd Tanous 37231e6deaf6SEd Tanous std::string msg = 37241e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 37251e6deaf6SEd Tanous if (msg.empty()) 3726a3316fc6SZhikuiRen { 37271e6deaf6SEd Tanous messages::internalError(asyncResp->res); 37281e6deaf6SEd Tanous return false; 3729a3316fc6SZhikuiRen } 3730a3316fc6SZhikuiRen 3731d4342a92STim Lee // Get Severity template from message registry 3732d4342a92STim Lee std::string severity; 3733d4342a92STim Lee if (message != nullptr) 3734d4342a92STim Lee { 37355f2b84eeSEd Tanous severity = message->messageSeverity; 3736d4342a92STim Lee } 3737d4342a92STim Lee 37386f284d24SJiaqing Zhao // Format entry 37396f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37409c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3741ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 3742253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 3743253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 374484afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 374584afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 374684afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 374784afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 37481e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 374984afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 375084afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 375184afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3752647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3753647b3cdcSGeorge Liu { 3754647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3755253f11b8SEd Tanous std::format( 3756253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 3757253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3758647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3759647b3cdcSGeorge Liu } 37606f284d24SJiaqing Zhao 37616f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 37626f284d24SJiaqing Zhao // that entry in this case 37636f284d24SJiaqing Zhao if (codeIndex != 0) 37646f284d24SJiaqing Zhao { 3765ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 37666f284d24SJiaqing Zhao return true; 3767a3316fc6SZhikuiRen } 37686f284d24SJiaqing Zhao 3769ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3770b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 37716f284d24SJiaqing Zhao } 37726f284d24SJiaqing Zhao 37736f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 37746f284d24SJiaqing Zhao return false; 3775a3316fc6SZhikuiRen } 3776a3316fc6SZhikuiRen 3777ac106bf6SEd Tanous static void 3778ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 37796f284d24SJiaqing Zhao const std::string& entryId) 3780a3316fc6SZhikuiRen { 37816f284d24SJiaqing Zhao uint16_t bootIndex = 0; 37826f284d24SJiaqing Zhao uint64_t codeIndex = 0; 37836f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 37846f284d24SJiaqing Zhao { 37856f284d24SJiaqing Zhao // Requested ID was not found 3786ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 37876f284d24SJiaqing Zhao return; 37886f284d24SJiaqing Zhao } 37896f284d24SJiaqing Zhao 37906f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 37916f284d24SJiaqing Zhao { 37926f284d24SJiaqing Zhao // 0 is an invalid index 3793ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 37946f284d24SJiaqing Zhao return; 37956f284d24SJiaqing Zhao } 37966f284d24SJiaqing Zhao 3797a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3798ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 37995e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 38006c9a279eSManojkiran Eda const boost::container::flat_map< 38016c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38026c9a279eSManojkiran Eda postcode) { 3803a3316fc6SZhikuiRen if (ec) 3804a3316fc6SZhikuiRen { 380562598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3806ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3807a3316fc6SZhikuiRen return; 3808a3316fc6SZhikuiRen } 3809a3316fc6SZhikuiRen 3810a3316fc6SZhikuiRen if (postcode.empty()) 3811a3316fc6SZhikuiRen { 3812ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3813a3316fc6SZhikuiRen return; 3814a3316fc6SZhikuiRen } 3815a3316fc6SZhikuiRen 3816ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 38176f284d24SJiaqing Zhao { 3818ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38196f284d24SJiaqing Zhao return; 38206f284d24SJiaqing Zhao } 3821a3316fc6SZhikuiRen }, 382215124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 382315124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3824a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3825a3316fc6SZhikuiRen bootIndex); 3826a3316fc6SZhikuiRen } 3827a3316fc6SZhikuiRen 3828ac106bf6SEd Tanous static void 3829ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3830ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3831ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3832a3316fc6SZhikuiRen { 3833a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3834ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 38355e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 38366c9a279eSManojkiran Eda const boost::container::flat_map< 38376c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38386c9a279eSManojkiran Eda postcode) { 3839a3316fc6SZhikuiRen if (ec) 3840a3316fc6SZhikuiRen { 384162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3842ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3843a3316fc6SZhikuiRen return; 3844a3316fc6SZhikuiRen } 3845a3316fc6SZhikuiRen 3846a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3847a3316fc6SZhikuiRen if (!postcode.empty()) 3848a3316fc6SZhikuiRen { 3849a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38503648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3851a3316fc6SZhikuiRen { 385289492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 385389492a15SPatrick Williams entryCount) - 38543648c8beSEd Tanous entryCount; 3855a3316fc6SZhikuiRen uint64_t thisBootTop = 38563648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38573648c8beSEd Tanous entryCount; 3858a3316fc6SZhikuiRen 3859ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3860ac106bf6SEd Tanous thisBootSkip, thisBootTop); 3861a3316fc6SZhikuiRen } 3862ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3863a3316fc6SZhikuiRen } 3864a3316fc6SZhikuiRen 3865a3316fc6SZhikuiRen // continue to previous bootIndex 3866a3316fc6SZhikuiRen if (bootIndex < bootCount) 3867a3316fc6SZhikuiRen { 3868ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 3869a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3870a3316fc6SZhikuiRen } 387181584abeSJiaqing Zhao else if (skip + top < endCount) 3872a3316fc6SZhikuiRen { 3873ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 3874253f11b8SEd Tanous std::format( 3875253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 3876253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3877a3316fc6SZhikuiRen std::to_string(skip + top); 3878a3316fc6SZhikuiRen } 3879a3316fc6SZhikuiRen }, 388015124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 388115124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3882a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3883a3316fc6SZhikuiRen bootIndex); 3884a3316fc6SZhikuiRen } 3885a3316fc6SZhikuiRen 38868d1b46d7Szhanghch05 static void 3887ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 38883648c8beSEd Tanous size_t skip, size_t top) 3889a3316fc6SZhikuiRen { 3890a3316fc6SZhikuiRen uint64_t entryCount = 0; 38911e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 38921e1e598dSJonathan Doman *crow::connections::systemBus, 38931e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 38941e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 38951e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 3896ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 38971e1e598dSJonathan Doman const uint16_t bootCount) { 3898a3316fc6SZhikuiRen if (ec) 3899a3316fc6SZhikuiRen { 390062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 3901ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3902a3316fc6SZhikuiRen return; 3903a3316fc6SZhikuiRen } 3904ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 39051e1e598dSJonathan Doman }); 3906a3316fc6SZhikuiRen } 3907a3316fc6SZhikuiRen 39087e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3909a3316fc6SZhikuiRen { 39107e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 391122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3912ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 39137e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 391445ca1b86SEd Tanous [&app](const crow::Request& req, 391522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 391622d268cbSEd Tanous const std::string& systemName) { 3917c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3918c937d2bfSEd Tanous .canDelegateTop = true, 3919c937d2bfSEd Tanous .canDelegateSkip = true, 3920c937d2bfSEd Tanous }; 3921c937d2bfSEd Tanous query_param::Query delegatedQuery; 3922c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39233ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 392445ca1b86SEd Tanous { 392545ca1b86SEd Tanous return; 392645ca1b86SEd Tanous } 392725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39287f3e84a1SEd Tanous { 39297f3e84a1SEd Tanous // Option currently returns no systems. TBD 39307f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39317f3e84a1SEd Tanous systemName); 39327f3e84a1SEd Tanous return; 39337f3e84a1SEd Tanous } 393422d268cbSEd Tanous 3935253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 393622d268cbSEd Tanous { 393722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 393822d268cbSEd Tanous systemName); 393922d268cbSEd Tanous return; 394022d268cbSEd Tanous } 3941a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3942a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3943a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3944253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3945253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3946a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3947a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3948a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3949a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3950a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39513648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39525143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39533648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39547e860f15SJohn Edward Broadbent }); 3955a3316fc6SZhikuiRen } 3956a3316fc6SZhikuiRen 3957647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3958647b3cdcSGeorge Liu { 39590fda0f12SGeorge Liu BMCWEB_ROUTE( 39600fda0f12SGeorge Liu app, 396122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3962647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3963647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 396445ca1b86SEd Tanous [&app](const crow::Request& req, 3965647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 396622d268cbSEd Tanous const std::string& systemName, 3967647b3cdcSGeorge Liu const std::string& postCodeID) { 39683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 396945ca1b86SEd Tanous { 397045ca1b86SEd Tanous return; 397145ca1b86SEd Tanous } 397272e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 397399351cd8SEd Tanous req.getHeaderValue("Accept"), 39744a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3975647b3cdcSGeorge Liu { 3976002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3977647b3cdcSGeorge Liu return; 3978647b3cdcSGeorge Liu } 397925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39807f3e84a1SEd Tanous { 39817f3e84a1SEd Tanous // Option currently returns no systems. TBD 39827f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39837f3e84a1SEd Tanous systemName); 39847f3e84a1SEd Tanous return; 39857f3e84a1SEd Tanous } 3986253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 398722d268cbSEd Tanous { 398822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 398922d268cbSEd Tanous systemName); 399022d268cbSEd Tanous return; 399122d268cbSEd Tanous } 3992647b3cdcSGeorge Liu 3993647b3cdcSGeorge Liu uint64_t currentValue = 0; 3994647b3cdcSGeorge Liu uint16_t index = 0; 3995647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3996647b3cdcSGeorge Liu { 3997002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3998647b3cdcSGeorge Liu return; 3999647b3cdcSGeorge Liu } 4000647b3cdcSGeorge Liu 4001647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4002647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 40035e7e2dc5SEd Tanous const boost::system::error_code& ec, 4004002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4005002d39b4SEd Tanous postcodes) { 4006647b3cdcSGeorge Liu if (ec.value() == EBADR) 4007647b3cdcSGeorge Liu { 4008002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4009002d39b4SEd Tanous postCodeID); 4010647b3cdcSGeorge Liu return; 4011647b3cdcSGeorge Liu } 4012647b3cdcSGeorge Liu if (ec) 4013647b3cdcSGeorge Liu { 401462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4015647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4016647b3cdcSGeorge Liu return; 4017647b3cdcSGeorge Liu } 4018647b3cdcSGeorge Liu 4019647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4020002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4021647b3cdcSGeorge Liu { 402262598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4023002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4024002d39b4SEd Tanous postCodeID); 4025647b3cdcSGeorge Liu return; 4026647b3cdcSGeorge Liu } 4027647b3cdcSGeorge Liu 40289eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 402946ff87baSEd Tanous if (c.empty()) 4030647b3cdcSGeorge Liu { 403162598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4032002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4033002d39b4SEd Tanous postCodeID); 4034647b3cdcSGeorge Liu return; 4035647b3cdcSGeorge Liu } 403646ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 403746ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 403846ff87baSEd Tanous std::string_view strData(d, c.size()); 4039647b3cdcSGeorge Liu 4040d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4041647b3cdcSGeorge Liu "application/octet-stream"); 4042d9f6c621SEd Tanous asyncResp->res.addHeader( 4043d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 404427b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4045647b3cdcSGeorge Liu }, 4046647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4047647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4048002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4049647b3cdcSGeorge Liu }); 4050647b3cdcSGeorge Liu } 4051647b3cdcSGeorge Liu 40527e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4053a3316fc6SZhikuiRen { 40547e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 405522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4056ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40577e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 405845ca1b86SEd Tanous [&app](const crow::Request& req, 40597e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 406022d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 406245ca1b86SEd Tanous { 406345ca1b86SEd Tanous return; 406445ca1b86SEd Tanous } 406525b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 40667f3e84a1SEd Tanous { 40677f3e84a1SEd Tanous // Option currently returns no systems. TBD 40687f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 40697f3e84a1SEd Tanous systemName); 40707f3e84a1SEd Tanous return; 40717f3e84a1SEd Tanous } 4072253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 407322d268cbSEd Tanous { 407422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 407522d268cbSEd Tanous systemName); 407622d268cbSEd Tanous return; 407722d268cbSEd Tanous } 407822d268cbSEd Tanous 40796f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 40807e860f15SJohn Edward Broadbent }); 4081a3316fc6SZhikuiRen } 4082a3316fc6SZhikuiRen 40831da66f75SEd Tanous } // namespace redfish 4084