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" 22539d8c6bSEd Tanous #include "generated/enums/log_service.hpp" 23b7028ebfSSpencer Ku #include "gzfile.hpp" 24647b3cdcSGeorge Liu #include "http_utility.hpp" 25b7028ebfSSpencer Ku #include "human_sort.hpp" 263ccb3adbSEd Tanous #include "query.hpp" 274851d45dSJason M. Bills #include "registries.hpp" 284851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 294851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 303ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 3146229577SJames Feist #include "task.hpp" 325b90429aSEd Tanous #include "task_messages.hpp" 333ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 345b90429aSEd Tanous #include "utils/json_utils.hpp" 353ccb3adbSEd Tanous #include "utils/time_utils.hpp" 361da66f75SEd Tanous 3775e8e218SMyung Bae #include <systemd/sd-id128.h> 388e31778eSAsmitha Karunanithi #include <tinyxml2.h> 39400fd1fbSAdriana Kobylak #include <unistd.h> 40e1f26343SJason M. Bills 4107c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 421da66f75SEd Tanous #include <boost/container/flat_map.hpp> 431ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 44ef4c65b7SEd Tanous #include <boost/url/format.hpp> 45d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 46d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 471214b7e7SGunnar Mills 487a1dbc48SGeorge Liu #include <array> 49647b3cdcSGeorge Liu #include <charconv> 50b5f288d2SAbhilash Raju #include <cstddef> 514418c7f0SJames Feist #include <filesystem> 5218f8f608SEd Tanous #include <iterator> 5375710de2SXiaochao Ma #include <optional> 543544d2a7SEd Tanous #include <ranges> 5526702d01SEd Tanous #include <span> 5618f8f608SEd Tanous #include <string> 57cd225da8SJason M. Bills #include <string_view> 58abf2add6SEd Tanous #include <variant> 591da66f75SEd Tanous 601da66f75SEd Tanous namespace redfish 611da66f75SEd Tanous { 621da66f75SEd Tanous 6389492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6489492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6589492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6689492a15SPatrick Williams constexpr const char* deleteAllInterface = 675b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6889492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 69424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 7089492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 716eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 721da66f75SEd Tanous 738e31778eSAsmitha Karunanithi enum class DumpCreationProgress 748e31778eSAsmitha Karunanithi { 758e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 768e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 778e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 788e31778eSAsmitha Karunanithi }; 798e31778eSAsmitha Karunanithi 80f6150403SJames Feist namespace fs = std::filesystem; 811da66f75SEd Tanous 82cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 83cb92c03bSAndrew Geissler { 84d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 86d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 87d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 88cb92c03bSAndrew Geissler { 89cb92c03bSAndrew Geissler return "Critical"; 90cb92c03bSAndrew Geissler } 913174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 92d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 93d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 94cb92c03bSAndrew Geissler { 95cb92c03bSAndrew Geissler return "OK"; 96cb92c03bSAndrew Geissler } 973174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 98cb92c03bSAndrew Geissler { 99cb92c03bSAndrew Geissler return "Warning"; 100cb92c03bSAndrew Geissler } 101cb92c03bSAndrew Geissler return ""; 102cb92c03bSAndrew Geissler } 103cb92c03bSAndrew Geissler 1049017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1059017faf2SAbhishek Patel { 1069017faf2SAbhishek Patel std::optional<bool> notifyAction; 1079017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1089017faf2SAbhishek Patel { 1099017faf2SAbhishek Patel notifyAction = true; 1109017faf2SAbhishek Patel } 1119017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1129017faf2SAbhishek Patel { 1139017faf2SAbhishek Patel notifyAction = false; 1149017faf2SAbhishek Patel } 1159017faf2SAbhishek Patel 1169017faf2SAbhishek Patel return notifyAction; 1179017faf2SAbhishek Patel } 1189017faf2SAbhishek Patel 11918f8f608SEd Tanous inline std::string getDumpPath(std::string_view dumpType) 12018f8f608SEd Tanous { 12118f8f608SEd Tanous std::string dbusDumpPath = "/xyz/openbmc_project/dump/"; 12218f8f608SEd Tanous std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath), 12318f8f608SEd Tanous bmcweb::asciiToLower); 12418f8f608SEd Tanous 12518f8f608SEd Tanous return dbusDumpPath; 12618f8f608SEd Tanous } 12718f8f608SEd Tanous 128055713e4SEd Tanous inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 129e85d6b16SJason M. Bills const bool firstEntry = true) 13095820184SJason M. Bills { 131271584abSEd Tanous static time_t prevTs = 0; 13295820184SJason M. Bills static int index = 0; 133e85d6b16SJason M. Bills if (firstEntry) 134e85d6b16SJason M. Bills { 135e85d6b16SJason M. Bills prevTs = 0; 136e85d6b16SJason M. Bills } 137e85d6b16SJason M. Bills 13895820184SJason M. Bills // Get the entry timestamp 139271584abSEd Tanous std::time_t curTs = 0; 14095820184SJason M. Bills std::tm timeStruct = {}; 14195820184SJason M. Bills std::istringstream entryStream(logEntry); 14295820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 14395820184SJason M. Bills { 14495820184SJason M. Bills curTs = std::mktime(&timeStruct); 14595820184SJason M. Bills } 14695820184SJason M. Bills // If the timestamp isn't unique, increment the index 14795820184SJason M. Bills if (curTs == prevTs) 14895820184SJason M. Bills { 14995820184SJason M. Bills index++; 15095820184SJason M. Bills } 15195820184SJason M. Bills else 15295820184SJason M. Bills { 15395820184SJason M. Bills // Otherwise, reset it 15495820184SJason M. Bills index = 0; 15595820184SJason M. Bills } 15695820184SJason M. Bills // Save the timestamp 15795820184SJason M. Bills prevTs = curTs; 15895820184SJason M. Bills 15995820184SJason M. Bills entryID = std::to_string(curTs); 16095820184SJason M. Bills if (index > 0) 16195820184SJason M. Bills { 16295820184SJason M. Bills entryID += "_" + std::to_string(index); 16395820184SJason M. Bills } 16495820184SJason M. Bills return true; 16595820184SJason M. Bills } 16695820184SJason M. Bills 16795820184SJason M. Bills static bool 16895820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 16995820184SJason M. Bills { 17095820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 17195820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 17295820184SJason M. Bills 17395820184SJason M. Bills // Loop through the directory looking for redfish log files 17495820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 17595820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 17695820184SJason M. Bills { 17795820184SJason M. Bills // If we find a redfish log file, save the path 17895820184SJason M. Bills std::string filename = dirEnt.path().filename(); 17911ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 18095820184SJason M. Bills { 18195820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 18295820184SJason M. Bills } 18395820184SJason M. Bills } 18495820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 18595820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 18695820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 1873544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 18895820184SJason M. Bills 18995820184SJason M. Bills return !redfishLogFiles.empty(); 19095820184SJason M. Bills } 19195820184SJason M. Bills 19268dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 19368dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 19468dd075aSAsmitha Karunanithi { 19568dd075aSAsmitha Karunanithi if (originatorType == 19668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 19768dd075aSAsmitha Karunanithi { 19868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 19968dd075aSAsmitha Karunanithi } 20068dd075aSAsmitha Karunanithi if (originatorType == 20168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 20268dd075aSAsmitha Karunanithi { 20368dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 20468dd075aSAsmitha Karunanithi } 20568dd075aSAsmitha Karunanithi if (originatorType == 20668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 20768dd075aSAsmitha Karunanithi { 20868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 20968dd075aSAsmitha Karunanithi } 21068dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 21168dd075aSAsmitha Karunanithi } 21268dd075aSAsmitha Karunanithi 213aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 2142d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 215c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 21668dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 217aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 218aefe3786SClaire Weinan { 219aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 220aefe3786SClaire Weinan { 221aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 222aefe3786SClaire Weinan { 223aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 224aefe3786SClaire Weinan { 225aefe3786SClaire Weinan if (propertyMap.first == "Status") 226aefe3786SClaire Weinan { 227aefe3786SClaire Weinan const auto* status = 228aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 229aefe3786SClaire Weinan if (status == nullptr) 230aefe3786SClaire Weinan { 231aefe3786SClaire Weinan messages::internalError(asyncResp->res); 232aefe3786SClaire Weinan break; 233aefe3786SClaire Weinan } 234aefe3786SClaire Weinan dumpStatus = *status; 235aefe3786SClaire Weinan } 236aefe3786SClaire Weinan } 237aefe3786SClaire Weinan } 238aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 239aefe3786SClaire Weinan { 240aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 241aefe3786SClaire Weinan { 242aefe3786SClaire Weinan if (propertyMap.first == "Size") 243aefe3786SClaire Weinan { 244aefe3786SClaire Weinan const auto* sizePtr = 245aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 246aefe3786SClaire Weinan if (sizePtr == nullptr) 247aefe3786SClaire Weinan { 248aefe3786SClaire Weinan messages::internalError(asyncResp->res); 249aefe3786SClaire Weinan break; 250aefe3786SClaire Weinan } 251aefe3786SClaire Weinan size = *sizePtr; 252aefe3786SClaire Weinan break; 253aefe3786SClaire Weinan } 254aefe3786SClaire Weinan } 255aefe3786SClaire Weinan } 256aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 257aefe3786SClaire Weinan { 258aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 259aefe3786SClaire Weinan { 260aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 261aefe3786SClaire Weinan { 262aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 263aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 264aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 265aefe3786SClaire Weinan { 266aefe3786SClaire Weinan messages::internalError(asyncResp->res); 267aefe3786SClaire Weinan break; 268aefe3786SClaire Weinan } 269c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 270aefe3786SClaire Weinan break; 271aefe3786SClaire Weinan } 272aefe3786SClaire Weinan } 273aefe3786SClaire Weinan } 27468dd075aSAsmitha Karunanithi else if (interfaceMap.first == 27568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 27668dd075aSAsmitha Karunanithi { 27768dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 27868dd075aSAsmitha Karunanithi { 27968dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 28068dd075aSAsmitha Karunanithi { 28168dd075aSAsmitha Karunanithi const std::string* id = 28268dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 28368dd075aSAsmitha Karunanithi if (id == nullptr) 28468dd075aSAsmitha Karunanithi { 28568dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 28668dd075aSAsmitha Karunanithi break; 28768dd075aSAsmitha Karunanithi } 28868dd075aSAsmitha Karunanithi originatorId = *id; 28968dd075aSAsmitha Karunanithi } 29068dd075aSAsmitha Karunanithi 29168dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 29268dd075aSAsmitha Karunanithi { 29368dd075aSAsmitha Karunanithi const std::string* type = 29468dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 29568dd075aSAsmitha Karunanithi if (type == nullptr) 29668dd075aSAsmitha Karunanithi { 29768dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 29868dd075aSAsmitha Karunanithi break; 29968dd075aSAsmitha Karunanithi } 30068dd075aSAsmitha Karunanithi 30168dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 30268dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 30368dd075aSAsmitha Karunanithi { 30468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 30568dd075aSAsmitha Karunanithi break; 30668dd075aSAsmitha Karunanithi } 30768dd075aSAsmitha Karunanithi } 30868dd075aSAsmitha Karunanithi } 30968dd075aSAsmitha Karunanithi } 310aefe3786SClaire Weinan } 311aefe3786SClaire Weinan } 312aefe3786SClaire Weinan 31321ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 314fdd26906SClaire Weinan { 315fdd26906SClaire Weinan std::string entriesPath; 316fdd26906SClaire Weinan 317fdd26906SClaire Weinan if (dumpType == "BMC") 318fdd26906SClaire Weinan { 319253f11b8SEd Tanous entriesPath = 320253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 321253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 322fdd26906SClaire Weinan } 323fdd26906SClaire Weinan else if (dumpType == "FaultLog") 324fdd26906SClaire Weinan { 325253f11b8SEd Tanous entriesPath = 326253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/FaultLog/Entries/", 327253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 328fdd26906SClaire Weinan } 329fdd26906SClaire Weinan else if (dumpType == "System") 330fdd26906SClaire Weinan { 331253f11b8SEd Tanous entriesPath = 332253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 333253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 334fdd26906SClaire Weinan } 335fdd26906SClaire Weinan else 336fdd26906SClaire Weinan { 33762598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 33862598e31SEd Tanous dumpType); 339fdd26906SClaire Weinan } 340fdd26906SClaire Weinan 341fdd26906SClaire Weinan // Returns empty string on error 342fdd26906SClaire Weinan return entriesPath; 343fdd26906SClaire Weinan } 344fdd26906SClaire Weinan 3458d1b46d7Szhanghch05 inline void 3468d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3475cb1dd27SAsmitha Karunanithi const std::string& dumpType) 3485cb1dd27SAsmitha Karunanithi { 349fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 350fdd26906SClaire Weinan if (entriesPath.empty()) 3515cb1dd27SAsmitha Karunanithi { 3525cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 3535cb1dd27SAsmitha Karunanithi return; 3545cb1dd27SAsmitha Karunanithi } 3555cb1dd27SAsmitha Karunanithi 3565eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 3575eb468daSGeorge Liu dbus::utility::getManagedObjects( 3585eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 359fdd26906SClaire Weinan [asyncResp, entriesPath, 3605e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 3615eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 3625cb1dd27SAsmitha Karunanithi if (ec) 3635cb1dd27SAsmitha Karunanithi { 36462598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 3655cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 3665cb1dd27SAsmitha Karunanithi return; 3675cb1dd27SAsmitha Karunanithi } 3685cb1dd27SAsmitha Karunanithi 369fdd26906SClaire Weinan // Remove ending slash 370fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 371fdd26906SClaire Weinan if (!odataIdStr.empty()) 372fdd26906SClaire Weinan { 373fdd26906SClaire Weinan odataIdStr.pop_back(); 374fdd26906SClaire Weinan } 375fdd26906SClaire Weinan 376fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 377fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 378fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 379fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 38089492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 38189492a15SPatrick Williams " Dump Entries"; 382fdd26906SClaire Weinan 3833544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 38418f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 3855cb1dd27SAsmitha Karunanithi 3865eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 3873544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 388002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 389002d39b4SEd Tanous r.first.filename()); 390565dfb6fSClaire Weinan }); 391565dfb6fSClaire Weinan 3925cb1dd27SAsmitha Karunanithi for (auto& object : resp) 3935cb1dd27SAsmitha Karunanithi { 394b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 3955cb1dd27SAsmitha Karunanithi { 3965cb1dd27SAsmitha Karunanithi continue; 3975cb1dd27SAsmitha Karunanithi } 398c6fecdabSClaire Weinan uint64_t timestampUs = 0; 3995cb1dd27SAsmitha Karunanithi uint64_t size = 0; 40035440d18SAsmitha Karunanithi std::string dumpStatus; 40168dd075aSAsmitha Karunanithi std::string originatorId; 40268dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 40368dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 404433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 4052dfd18efSEd Tanous 4062dfd18efSEd Tanous std::string entryID = object.first.filename(); 4072dfd18efSEd Tanous if (entryID.empty()) 4085cb1dd27SAsmitha Karunanithi { 4095cb1dd27SAsmitha Karunanithi continue; 4105cb1dd27SAsmitha Karunanithi } 4115cb1dd27SAsmitha Karunanithi 412c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 41368dd075aSAsmitha Karunanithi originatorId, originatorType, 414aefe3786SClaire Weinan asyncResp); 4155cb1dd27SAsmitha Karunanithi 4160fda0f12SGeorge Liu if (dumpStatus != 4170fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 41835440d18SAsmitha Karunanithi !dumpStatus.empty()) 41935440d18SAsmitha Karunanithi { 42035440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 42135440d18SAsmitha Karunanithi continue; 42235440d18SAsmitha Karunanithi } 42335440d18SAsmitha Karunanithi 42468dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 425fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 4265cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 4275cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 4285cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 429bbd80db8SClaire Weinan thisEntry["Created"] = 430bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 4315cb1dd27SAsmitha Karunanithi 43268dd075aSAsmitha Karunanithi if (!originatorId.empty()) 43368dd075aSAsmitha Karunanithi { 43468dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 43568dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 43668dd075aSAsmitha Karunanithi } 43768dd075aSAsmitha Karunanithi 4385cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 4395cb1dd27SAsmitha Karunanithi { 440d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 44189492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 44289492a15SPatrick Williams "/attachment"; 443fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 4445cb1dd27SAsmitha Karunanithi } 4455cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 4465cb1dd27SAsmitha Karunanithi { 447d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 448d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 44989492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 45089492a15SPatrick Williams "/attachment"; 451fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 4525cb1dd27SAsmitha Karunanithi } 453b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 4545cb1dd27SAsmitha Karunanithi } 455002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 4563544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 4575eb468daSGeorge Liu }); 4585cb1dd27SAsmitha Karunanithi } 4595cb1dd27SAsmitha Karunanithi 4608d1b46d7Szhanghch05 inline void 461c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4628d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 4635cb1dd27SAsmitha Karunanithi { 464fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 465fdd26906SClaire Weinan if (entriesPath.empty()) 4665cb1dd27SAsmitha Karunanithi { 4675cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4685cb1dd27SAsmitha Karunanithi return; 4695cb1dd27SAsmitha Karunanithi } 4705cb1dd27SAsmitha Karunanithi 4715eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4725eb468daSGeorge Liu dbus::utility::getManagedObjects( 4735eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 474fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 4755e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 47602cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 4775cb1dd27SAsmitha Karunanithi if (ec) 4785cb1dd27SAsmitha Karunanithi { 47962598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 4805cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4815cb1dd27SAsmitha Karunanithi return; 4825cb1dd27SAsmitha Karunanithi } 4835cb1dd27SAsmitha Karunanithi 484b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 48518f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 486b47452b2SAsmitha Karunanithi 4879eb808c1SEd Tanous for (const auto& objectPath : resp) 4885cb1dd27SAsmitha Karunanithi { 489b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 4905cb1dd27SAsmitha Karunanithi { 4915cb1dd27SAsmitha Karunanithi continue; 4925cb1dd27SAsmitha Karunanithi } 4935cb1dd27SAsmitha Karunanithi 4945cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 495c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4965cb1dd27SAsmitha Karunanithi uint64_t size = 0; 49735440d18SAsmitha Karunanithi std::string dumpStatus; 49868dd075aSAsmitha Karunanithi std::string originatorId; 49968dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 50068dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 5015cb1dd27SAsmitha Karunanithi 502aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 50368dd075aSAsmitha Karunanithi timestampUs, originatorId, 50468dd075aSAsmitha Karunanithi originatorType, asyncResp); 5055cb1dd27SAsmitha Karunanithi 5060fda0f12SGeorge Liu if (dumpStatus != 5070fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 50835440d18SAsmitha Karunanithi !dumpStatus.empty()) 50935440d18SAsmitha Karunanithi { 51035440d18SAsmitha Karunanithi // Dump status is not Complete 51135440d18SAsmitha Karunanithi // return not found until status is changed to Completed 512d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 513d1bde9e5SKrzysztof Grobelny entryID); 51435440d18SAsmitha Karunanithi return; 51535440d18SAsmitha Karunanithi } 51635440d18SAsmitha Karunanithi 5175cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 51868dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 519fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5205cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 5215cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 5225cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 523bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 524bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5255cb1dd27SAsmitha Karunanithi 52668dd075aSAsmitha Karunanithi if (!originatorId.empty()) 52768dd075aSAsmitha Karunanithi { 52868dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 52968dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 53068dd075aSAsmitha Karunanithi } 53168dd075aSAsmitha Karunanithi 5325cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5335cb1dd27SAsmitha Karunanithi { 534d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 535d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 536fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 537fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5385cb1dd27SAsmitha Karunanithi } 5395cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5405cb1dd27SAsmitha Karunanithi { 541d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 542002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 543d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 544fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 545fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5465cb1dd27SAsmitha Karunanithi } 5475cb1dd27SAsmitha Karunanithi } 548e05aec50SEd Tanous if (!foundDumpEntry) 549b47452b2SAsmitha Karunanithi { 55062598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 551b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 552b90d14f2SMyung Bae entryID); 553b47452b2SAsmitha Karunanithi return; 554b47452b2SAsmitha Karunanithi } 5555eb468daSGeorge Liu }); 5565cb1dd27SAsmitha Karunanithi } 5575cb1dd27SAsmitha Karunanithi 5588d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5599878256fSStanley Chu const std::string& entryID, 560b47452b2SAsmitha Karunanithi const std::string& dumpType) 5615cb1dd27SAsmitha Karunanithi { 5625a39f77aSPatrick Williams auto respHandler = [asyncResp, 5635a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 56462598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 5655cb1dd27SAsmitha Karunanithi if (ec) 5665cb1dd27SAsmitha Karunanithi { 5673de8d8baSGeorge Liu if (ec.value() == EBADR) 5683de8d8baSGeorge Liu { 5693de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 5703de8d8baSGeorge Liu return; 5713de8d8baSGeorge Liu } 57262598e31SEd Tanous BMCWEB_LOG_ERROR( 57362598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 57462598e31SEd Tanous entryID); 5755cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5765cb1dd27SAsmitha Karunanithi return; 5775cb1dd27SAsmitha Karunanithi } 5785cb1dd27SAsmitha Karunanithi }; 57918f8f608SEd Tanous 5805cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 5815cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 58218f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 5835cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 5845cb1dd27SAsmitha Karunanithi } 585b5f288d2SAbhilash Raju inline bool checkSizeLimit(int fd, crow::Response& res) 586b5f288d2SAbhilash Raju { 587b5f288d2SAbhilash Raju long long int size = lseek(fd, 0, SEEK_END); 588b5f288d2SAbhilash Raju if (size <= 0) 589b5f288d2SAbhilash Raju { 590b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 591b5f288d2SAbhilash Raju size); 592b5f288d2SAbhilash Raju messages::internalError(res); 593b5f288d2SAbhilash Raju return false; 594b5f288d2SAbhilash Raju } 5955cb1dd27SAsmitha Karunanithi 596b5f288d2SAbhilash Raju // Arbitrary max size of 20MB to accommodate BMC dumps 597b5f288d2SAbhilash Raju constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 598b5f288d2SAbhilash Raju if (size > maxFileSize) 599b5f288d2SAbhilash Raju { 600b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 601b5f288d2SAbhilash Raju size, maxFileSize); 602b5f288d2SAbhilash Raju messages::internalError(res); 603b5f288d2SAbhilash Raju return false; 604b5f288d2SAbhilash Raju } 605b5f288d2SAbhilash Raju off_t rc = lseek(fd, 0, SEEK_SET); 606b5f288d2SAbhilash Raju if (rc < 0) 607b5f288d2SAbhilash Raju { 608b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 609b5f288d2SAbhilash Raju messages::internalError(res); 610b5f288d2SAbhilash Raju return false; 611b5f288d2SAbhilash Raju } 612b5f288d2SAbhilash Raju return true; 613b5f288d2SAbhilash Raju } 614168d1b1aSCarson Labrado inline void 615168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 616168d1b1aSCarson Labrado const std::string& entryID, 617168d1b1aSCarson Labrado const std::string& downloadEntryType, 618168d1b1aSCarson Labrado const boost::system::error_code& ec, 619168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 620168d1b1aSCarson Labrado { 621168d1b1aSCarson Labrado if (ec.value() == EBADR) 622168d1b1aSCarson Labrado { 623168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 624168d1b1aSCarson Labrado return; 625168d1b1aSCarson Labrado } 626168d1b1aSCarson Labrado if (ec) 627168d1b1aSCarson Labrado { 628168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 629168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 630168d1b1aSCarson Labrado return; 631168d1b1aSCarson Labrado } 632168d1b1aSCarson Labrado 633168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 634168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 635168d1b1aSCarson Labrado { 636168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 637168d1b1aSCarson Labrado downloadEntryType); 638168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 639168d1b1aSCarson Labrado } 640168d1b1aSCarson Labrado 641168d1b1aSCarson Labrado int fd = -1; 642168d1b1aSCarson Labrado fd = dup(unixfd); 643168d1b1aSCarson Labrado if (fd < 0) 644168d1b1aSCarson Labrado { 645168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 646168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 647168d1b1aSCarson Labrado return; 648168d1b1aSCarson Labrado } 649b5f288d2SAbhilash Raju if (!checkSizeLimit(fd, asyncResp->res)) 650168d1b1aSCarson Labrado { 651168d1b1aSCarson Labrado close(fd); 652168d1b1aSCarson Labrado return; 653168d1b1aSCarson Labrado } 654168d1b1aSCarson Labrado if (downloadEntryType == "System") 655168d1b1aSCarson Labrado { 656b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 657b5f288d2SAbhilash Raju { 658b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 659b5f288d2SAbhilash Raju close(fd); 660b5f288d2SAbhilash Raju return; 661b5f288d2SAbhilash Raju } 662168d1b1aSCarson Labrado asyncResp->res.addHeader( 663168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 664b5f288d2SAbhilash Raju return; 665168d1b1aSCarson Labrado } 666b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd)) 66727b0cf90SEd Tanous { 668b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 669b5f288d2SAbhilash Raju close(fd); 670b5f288d2SAbhilash Raju return; 67127b0cf90SEd Tanous } 672168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 673168d1b1aSCarson Labrado "application/octet-stream"); 674168d1b1aSCarson Labrado } 675168d1b1aSCarson Labrado 676168d1b1aSCarson Labrado inline void 677168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 678168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 679168d1b1aSCarson Labrado { 680168d1b1aSCarson Labrado if (dumpType != "BMC") 681168d1b1aSCarson Labrado { 682168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 683168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 684168d1b1aSCarson Labrado return; 685168d1b1aSCarson Labrado } 686168d1b1aSCarson Labrado 68718f8f608SEd Tanous std::string dumpEntryPath = std::format("{}/entry/{}", 68818f8f608SEd Tanous getDumpPath(dumpType), entryID); 689168d1b1aSCarson Labrado 690168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 691168d1b1aSCarson Labrado [asyncResp, entryID, 692168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 693168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 694168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 695168d1b1aSCarson Labrado }; 696168d1b1aSCarson Labrado 697168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 698168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 699168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 700168d1b1aSCarson Labrado } 701168d1b1aSCarson Labrado 702168d1b1aSCarson Labrado inline void 703168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 704168d1b1aSCarson Labrado const std::string& systemName, 705168d1b1aSCarson Labrado const std::string& entryID, 706168d1b1aSCarson Labrado const std::string& dumpType) 707168d1b1aSCarson Labrado { 70825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 709168d1b1aSCarson Labrado { 710168d1b1aSCarson Labrado // Option currently returns no systems. TBD 711168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 712168d1b1aSCarson Labrado systemName); 713168d1b1aSCarson Labrado return; 714168d1b1aSCarson Labrado } 715253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 716168d1b1aSCarson Labrado { 717168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 718168d1b1aSCarson Labrado systemName); 719168d1b1aSCarson Labrado return; 720168d1b1aSCarson Labrado } 721168d1b1aSCarson Labrado 722168d1b1aSCarson Labrado std::string entryPath = 723168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 724168d1b1aSCarson Labrado entryID; 725168d1b1aSCarson Labrado 726168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 727168d1b1aSCarson Labrado [asyncResp, entryID, 728168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 729168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 730168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 731168d1b1aSCarson Labrado }; 732168d1b1aSCarson Labrado 733168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 734168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 735168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 736168d1b1aSCarson Labrado } 737168d1b1aSCarson Labrado 7388e31778eSAsmitha Karunanithi inline DumpCreationProgress 7398e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 740a43be80fSAsmitha Karunanithi { 7418e31778eSAsmitha Karunanithi if (status == 7428e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 7438e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 7448e31778eSAsmitha Karunanithi { 7458e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7468e31778eSAsmitha Karunanithi } 7478e31778eSAsmitha Karunanithi if (status == 7488e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 7498e31778eSAsmitha Karunanithi { 7508e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 7518e31778eSAsmitha Karunanithi } 7528e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7538e31778eSAsmitha Karunanithi } 7548e31778eSAsmitha Karunanithi 7558e31778eSAsmitha Karunanithi inline DumpCreationProgress 7568e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 7578e31778eSAsmitha Karunanithi { 7588e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 7598e31778eSAsmitha Karunanithi { 7608e31778eSAsmitha Karunanithi if (key == "Status") 7618e31778eSAsmitha Karunanithi { 7628e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 7638e31778eSAsmitha Karunanithi if (value == nullptr) 7648e31778eSAsmitha Karunanithi { 76562598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 7668e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7678e31778eSAsmitha Karunanithi } 7688e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 7698e31778eSAsmitha Karunanithi } 7708e31778eSAsmitha Karunanithi } 7718e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7728e31778eSAsmitha Karunanithi } 7738e31778eSAsmitha Karunanithi 7748e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7758e31778eSAsmitha Karunanithi { 7768e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7778e31778eSAsmitha Karunanithi { 778253f11b8SEd Tanous return std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 7799f565090SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 7808e31778eSAsmitha Karunanithi } 7818e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7828e31778eSAsmitha Karunanithi { 783253f11b8SEd Tanous return std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 784253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 7858e31778eSAsmitha Karunanithi } 7868e31778eSAsmitha Karunanithi return ""; 7878e31778eSAsmitha Karunanithi } 7888e31778eSAsmitha Karunanithi 7898e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7908e31778eSAsmitha Karunanithi task::Payload&& payload, 7918e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7928e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7938e31778eSAsmitha Karunanithi { 7948e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7958e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7968e31778eSAsmitha Karunanithi 7978e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7988e31778eSAsmitha Karunanithi 7998e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 8008e31778eSAsmitha Karunanithi { 80162598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 8028e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8038e31778eSAsmitha Karunanithi return; 8048e31778eSAsmitha Karunanithi } 8058e31778eSAsmitha Karunanithi 8068e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 8078cb2c024SEd Tanous [asyncResp, payload = std::move(payload), createdObjPath, 8088e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 8095e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 8108e31778eSAsmitha Karunanithi const std::string& introspectXml) { 8118e31778eSAsmitha Karunanithi if (ec) 8128e31778eSAsmitha Karunanithi { 81362598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 81462598e31SEd Tanous ec.message()); 8158e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8168e31778eSAsmitha Karunanithi return; 8178e31778eSAsmitha Karunanithi } 8188e31778eSAsmitha Karunanithi 8198e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 8208e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 8218e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 8228e31778eSAsmitha Karunanithi // Else, return task completed. 8238e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 8248e31778eSAsmitha Karunanithi 8258e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 8268e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 8278e31778eSAsmitha Karunanithi if (pRoot == nullptr) 8288e31778eSAsmitha Karunanithi { 82962598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 8308e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 8318e31778eSAsmitha Karunanithi return; 8328e31778eSAsmitha Karunanithi } 8338e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 8348e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 8358e31778eSAsmitha Karunanithi 8368e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 8378e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 8388e31778eSAsmitha Karunanithi { 8398e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 8408e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 8418e31778eSAsmitha Karunanithi { 8428e31778eSAsmitha Karunanithi if (thisInterfaceName == 8438e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 8448e31778eSAsmitha Karunanithi { 8458e31778eSAsmitha Karunanithi interfaceNode = 8468e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 8478e31778eSAsmitha Karunanithi continue; 8488e31778eSAsmitha Karunanithi } 8498e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 8508e31778eSAsmitha Karunanithi break; 8518e31778eSAsmitha Karunanithi } 8528e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 8538e31778eSAsmitha Karunanithi } 8548e31778eSAsmitha Karunanithi 855a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 8568e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 8578b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 858a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 8598b24275dSEd Tanous if (ec2) 860cb13a392SEd Tanous { 86162598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 86262598e31SEd Tanous createdObjPath.str); 8638e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 8646145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 8656145ed6fSAsmitha Karunanithi return task::completed; 866cb13a392SEd Tanous } 867b9d36b47SEd Tanous 8688e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 869a43be80fSAsmitha Karunanithi { 8708e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8718e31778eSAsmitha Karunanithi std::string prop; 8728e31778eSAsmitha Karunanithi msg.read(prop, values); 8738e31778eSAsmitha Karunanithi 8748e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8758e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8768e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8778e31778eSAsmitha Karunanithi { 87862598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 87962598e31SEd Tanous createdObjPath.str); 8808e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8818e31778eSAsmitha Karunanithi return task::completed; 8828e31778eSAsmitha Karunanithi } 8838e31778eSAsmitha Karunanithi 8848e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8858e31778eSAsmitha Karunanithi { 88662598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 88762598e31SEd Tanous createdObjPath.str); 8888e31778eSAsmitha Karunanithi return !task::completed; 8898e31778eSAsmitha Karunanithi } 8908e31778eSAsmitha Karunanithi } 8918e31778eSAsmitha Karunanithi 892a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 893a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 894a43be80fSAsmitha Karunanithi 895c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 896253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump/Entries/{}", 897253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, dumpId); 898c51a58eeSEd Tanous 899c51a58eeSEd Tanous std::string headerLoc = "Location: "; 900c51a58eeSEd Tanous headerLoc += url.buffer(); 901c51a58eeSEd Tanous 902002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 903a43be80fSAsmitha Karunanithi 90462598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 90562598e31SEd Tanous createdObjPath.str); 906a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 907b47452b2SAsmitha Karunanithi return task::completed; 908a43be80fSAsmitha Karunanithi }, 9098e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 9108e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 9118e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 912a43be80fSAsmitha Karunanithi 9138e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 9148e31778eSAsmitha Karunanithi // requested dump will be collected. 9158e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 916a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 9178e31778eSAsmitha Karunanithi task->payload.emplace(payload); 9188e31778eSAsmitha Karunanithi }, 9198e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 9208e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 921a43be80fSAsmitha Karunanithi } 922a43be80fSAsmitha Karunanithi 9238d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9248d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 925a43be80fSAsmitha Karunanithi { 926fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 927fdd26906SClaire Weinan if (dumpPath.empty()) 928a43be80fSAsmitha Karunanithi { 929a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 930a43be80fSAsmitha Karunanithi return; 931a43be80fSAsmitha Karunanithi } 932a43be80fSAsmitha Karunanithi 933a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 934a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 935a43be80fSAsmitha Karunanithi 93615ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 937a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 938a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 939a43be80fSAsmitha Karunanithi { 940a43be80fSAsmitha Karunanithi return; 941a43be80fSAsmitha Karunanithi } 942a43be80fSAsmitha Karunanithi 943a43be80fSAsmitha Karunanithi if (dumpType == "System") 944a43be80fSAsmitha Karunanithi { 945a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 946a43be80fSAsmitha Karunanithi { 94762598e31SEd Tanous BMCWEB_LOG_ERROR( 94862598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 949a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 950a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 951a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 952a43be80fSAsmitha Karunanithi return; 953a43be80fSAsmitha Karunanithi } 9543174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 955a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 956a43be80fSAsmitha Karunanithi { 95762598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 958ace85d60SEd Tanous messages::internalError(asyncResp->res); 959a43be80fSAsmitha Karunanithi return; 960a43be80fSAsmitha Karunanithi } 961253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump/", 962253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 963a43be80fSAsmitha Karunanithi } 964a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 965a43be80fSAsmitha Karunanithi { 966a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 967a43be80fSAsmitha Karunanithi { 96862598e31SEd Tanous BMCWEB_LOG_ERROR( 96962598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 970a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 971a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 972a43be80fSAsmitha Karunanithi return; 973a43be80fSAsmitha Karunanithi } 9743174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 975a43be80fSAsmitha Karunanithi { 97662598e31SEd Tanous BMCWEB_LOG_ERROR( 97762598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 978ace85d60SEd Tanous messages::internalError(asyncResp->res); 979a43be80fSAsmitha Karunanithi return; 980a43be80fSAsmitha Karunanithi } 981253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump/", 982253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 9835907571dSAsmitha Karunanithi } 9845907571dSAsmitha Karunanithi else 9855907571dSAsmitha Karunanithi { 98662598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 9875907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9885907571dSAsmitha Karunanithi return; 989a43be80fSAsmitha Karunanithi } 990a43be80fSAsmitha Karunanithi 9918e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9928e31778eSAsmitha Karunanithi createDumpParamVec; 9938e31778eSAsmitha Karunanithi 994f574a8e1SCarson Labrado if (req.session != nullptr) 995f574a8e1SCarson Labrado { 99668dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 99768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 99868dd075aSAsmitha Karunanithi req.session->clientIp); 99968dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 100068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 100168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1002f574a8e1SCarson Labrado } 100368dd075aSAsmitha Karunanithi 1004a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 10055e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 10065e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 10075e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 10088e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1009a43be80fSAsmitha Karunanithi if (ec) 1010a43be80fSAsmitha Karunanithi { 101162598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 10125907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 10135907571dSAsmitha Karunanithi if (dbusError == nullptr) 10145907571dSAsmitha Karunanithi { 10155907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 10165907571dSAsmitha Karunanithi return; 10175907571dSAsmitha Karunanithi } 10185907571dSAsmitha Karunanithi 101962598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 102062598e31SEd Tanous dbusError->name, dbusError->message); 10215907571dSAsmitha Karunanithi if (std::string_view( 10225907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 10235907571dSAsmitha Karunanithi dbusError->name) 10245907571dSAsmitha Karunanithi { 10255907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 10265907571dSAsmitha Karunanithi return; 10275907571dSAsmitha Karunanithi } 10285907571dSAsmitha Karunanithi if (std::string_view( 10295907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 10305907571dSAsmitha Karunanithi dbusError->name) 10315907571dSAsmitha Karunanithi { 10325907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 10335907571dSAsmitha Karunanithi return; 10345907571dSAsmitha Karunanithi } 10355907571dSAsmitha Karunanithi if (std::string_view( 10365907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 10375907571dSAsmitha Karunanithi dbusError->name) 10385907571dSAsmitha Karunanithi { 10395907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 10405907571dSAsmitha Karunanithi return; 10415907571dSAsmitha Karunanithi } 10425907571dSAsmitha Karunanithi // Other Dbus errors such as: 10435907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 10445907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 10455907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 10465907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 10475907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 10485907571dSAsmitha Karunanithi // back to the client. 1049a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1050a43be80fSAsmitha Karunanithi return; 1051a43be80fSAsmitha Karunanithi } 105262598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 10538e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1054a43be80fSAsmitha Karunanithi }, 105518f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10568e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1057a43be80fSAsmitha Karunanithi } 1058a43be80fSAsmitha Karunanithi 10598d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10608d1b46d7Szhanghch05 const std::string& dumpType) 106180319af1SAsmitha Karunanithi { 10620d946211SClaire Weinan crow::connections::systemBus->async_method_call( 10630d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 106480319af1SAsmitha Karunanithi if (ec) 106580319af1SAsmitha Karunanithi { 106662598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 106780319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 106880319af1SAsmitha Karunanithi return; 106980319af1SAsmitha Karunanithi } 10700d946211SClaire Weinan }, 107118f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10720d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 107380319af1SAsmitha Karunanithi } 107480319af1SAsmitha Karunanithi 1075df254f2cSEd Tanous inline void 1076b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1077b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1078b9d36b47SEd Tanous std::string& logfile) 1079043a0536SJohnathan Mantey { 1080d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1081d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1082d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1083d1bde9e5SKrzysztof Grobelny 1084d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1085d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1086d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1087d1bde9e5SKrzysztof Grobelny 1088d1bde9e5SKrzysztof Grobelny if (!success) 1089043a0536SJohnathan Mantey { 1090d1bde9e5SKrzysztof Grobelny return; 1091043a0536SJohnathan Mantey } 1092d1bde9e5SKrzysztof Grobelny 1093d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1094043a0536SJohnathan Mantey { 1095d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1096d1bde9e5SKrzysztof Grobelny } 1097d1bde9e5SKrzysztof Grobelny 1098d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1099043a0536SJohnathan Mantey { 1100d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1101043a0536SJohnathan Mantey } 1102d1bde9e5SKrzysztof Grobelny 1103d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1104043a0536SJohnathan Mantey { 1105d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1106043a0536SJohnathan Mantey } 1107043a0536SJohnathan Mantey } 1108043a0536SJohnathan Mantey 11097e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 11101da66f75SEd Tanous { 1111c4bf6374SJason M. Bills /** 1112c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1113c4bf6374SJason M. Bills */ 111422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1115ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1116002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1117002d39b4SEd Tanous [&app](const crow::Request& req, 111822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 111922d268cbSEd Tanous const std::string& systemName) { 11203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1121c4bf6374SJason M. Bills { 112245ca1b86SEd Tanous return; 112345ca1b86SEd Tanous } 112425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 11257f3e84a1SEd Tanous { 11267f3e84a1SEd Tanous // Option currently returns no systems. TBD 11277f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 11287f3e84a1SEd Tanous systemName); 11297f3e84a1SEd Tanous return; 11307f3e84a1SEd Tanous } 1131253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 113222d268cbSEd Tanous { 113322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 113422d268cbSEd Tanous systemName); 113522d268cbSEd Tanous return; 113622d268cbSEd Tanous } 113722d268cbSEd Tanous 11387e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 11397e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1140c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1141c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1142c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1143253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices", 1144253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 114545ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1146c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1147c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1148002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1149c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11501476687dSEd Tanous nlohmann::json::object_t eventLog; 11511476687dSEd Tanous eventLog["@odata.id"] = 1152253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1153253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1154b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 115525b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 115625b54dbaSEd Tanous { 11571476687dSEd Tanous nlohmann::json::object_t dumpLog; 115825b54dbaSEd Tanous dumpLog["@odata.id"] = 1159253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump", 1160253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1161b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 116225b54dbaSEd Tanous } 1163c9bb6861Sraviteja-b 11645ffd11f2SGunnar Mills if constexpr (BMCWEB_REDFISH_CPU_LOG) 116525b54dbaSEd Tanous { 11661476687dSEd Tanous nlohmann::json::object_t crashdump; 11671476687dSEd Tanous crashdump["@odata.id"] = 1168253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 1169253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1170b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 117125b54dbaSEd Tanous } 1172b7028ebfSSpencer Ku 117325b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_HOST_LOGGER) 117425b54dbaSEd Tanous { 11751476687dSEd Tanous nlohmann::json::object_t hostlogger; 11761476687dSEd Tanous hostlogger["@odata.id"] = 1177253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 1178253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1179b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 118025b54dbaSEd Tanous } 1181c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1182c4bf6374SJason M. Bills logServiceArray.size(); 1183a3316fc6SZhikuiRen 11847a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11857a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11867a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11877a1dbc48SGeorge Liu "/", 0, interfaces, 11887a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1189b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1190b9d36b47SEd Tanous subtreePath) { 1191a3316fc6SZhikuiRen if (ec) 1192a3316fc6SZhikuiRen { 119362598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1194a3316fc6SZhikuiRen return; 1195a3316fc6SZhikuiRen } 1196a3316fc6SZhikuiRen 119755f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1198a3316fc6SZhikuiRen { 1199a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1200a3316fc6SZhikuiRen { 120123a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1202a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1203613dabeaSEd Tanous nlohmann::json::object_t member; 1204253f11b8SEd Tanous member["@odata.id"] = std::format( 1205253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes", 1206253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1207613dabeaSEd Tanous 1208b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1209613dabeaSEd Tanous 121045ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 121123a21a1cSEd Tanous logServiceArrayLocal.size(); 1212a3316fc6SZhikuiRen return; 1213a3316fc6SZhikuiRen } 1214a3316fc6SZhikuiRen } 12157a1dbc48SGeorge Liu }); 12167e860f15SJohn Edward Broadbent }); 1217c4bf6374SJason M. Bills } 1218c4bf6374SJason M. Bills 12197e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1220c4bf6374SJason M. Bills { 122122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1222ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1223002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1224002d39b4SEd Tanous [&app](const crow::Request& req, 122522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 122622d268cbSEd Tanous const std::string& systemName) { 12273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 122845ca1b86SEd Tanous { 122945ca1b86SEd Tanous return; 123045ca1b86SEd Tanous } 1231253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 123222d268cbSEd Tanous { 123322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 123422d268cbSEd Tanous systemName); 123522d268cbSEd Tanous return; 123622d268cbSEd Tanous } 1237c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1238253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1239253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1240c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1241b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1242c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1243002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1244c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1245539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 1246539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 12477c8c4058STejas Patil 12487c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 12492b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 12507c8c4058STejas Patil 12517c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 12527c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 12537c8c4058STejas Patil redfishDateTimeOffset.second; 12547c8c4058STejas Patil 12551476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 1256253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1257253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 125820fa6a2cSEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] 1259e7d6c8b2SGunnar Mills 126020fa6a2cSEd Tanous = std::format( 1261253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog", 126220fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 12637e860f15SJohn Edward Broadbent }); 1264489640c6SJason M. Bills } 1265489640c6SJason M. Bills 1266*599b9af3SAlexander Hansen inline void handleSystemsLogServicesEventLogActionsClearPost( 1267*599b9af3SAlexander Hansen App& app, const crow::Request& req, 126822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1269*599b9af3SAlexander Hansen const std::string& systemName) 1270*599b9af3SAlexander Hansen { 12713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 127245ca1b86SEd Tanous { 127345ca1b86SEd Tanous return; 127445ca1b86SEd Tanous } 1275253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 127622d268cbSEd Tanous { 127722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 127822d268cbSEd Tanous systemName); 127922d268cbSEd Tanous return; 128022d268cbSEd Tanous } 1281*599b9af3SAlexander Hansen 1282489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1283489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1284489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1285489640c6SJason M. Bills { 1286489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1287489640c6SJason M. Bills { 1288489640c6SJason M. Bills std::error_code ec; 1289489640c6SJason M. Bills std::filesystem::remove(file, ec); 1290489640c6SJason M. Bills } 1291489640c6SJason M. Bills } 1292489640c6SJason M. Bills 1293489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1294489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 12955e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1296489640c6SJason M. Bills if (ec) 1297489640c6SJason M. Bills { 129862598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1299489640c6SJason M. Bills messages::internalError(asyncResp->res); 1300489640c6SJason M. Bills return; 1301489640c6SJason M. Bills } 1302489640c6SJason M. Bills 1303489640c6SJason M. Bills messages::success(asyncResp->res); 1304489640c6SJason M. Bills }, 1305489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1306002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1307002d39b4SEd Tanous "replace"); 1308*599b9af3SAlexander Hansen } 1309*599b9af3SAlexander Hansen 1310*599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogClear(App& app) 1311*599b9af3SAlexander Hansen { 1312*599b9af3SAlexander Hansen BMCWEB_ROUTE( 1313*599b9af3SAlexander Hansen app, 1314*599b9af3SAlexander Hansen "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1315*599b9af3SAlexander Hansen .privileges({{"ConfigureComponents"}}) 1316*599b9af3SAlexander Hansen .methods(boost::beast::http::verb::post)(std::bind_front( 1317*599b9af3SAlexander Hansen handleSystemsLogServicesEventLogActionsClearPost, std::ref(app))); 1318c4bf6374SJason M. Bills } 1319c4bf6374SJason M. Bills 1320ac992cdeSJason M. Bills enum class LogParseError 1321ac992cdeSJason M. Bills { 1322ac992cdeSJason M. Bills success, 1323ac992cdeSJason M. Bills parseFailed, 1324ac992cdeSJason M. Bills messageIdNotInRegistry, 1325ac992cdeSJason M. Bills }; 1326ac992cdeSJason M. Bills 1327ac992cdeSJason M. Bills static LogParseError 1328ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1329b5a76932SEd Tanous const std::string& logEntry, 1330de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1331c4bf6374SJason M. Bills { 133295820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1333cd225da8SJason M. Bills // First get the Timestamp 1334f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1335cd225da8SJason M. Bills if (space == std::string::npos) 133695820184SJason M. Bills { 1337ac992cdeSJason M. Bills return LogParseError::parseFailed; 133895820184SJason M. Bills } 1339cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1340cd225da8SJason M. Bills // Then get the log contents 1341f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1342cd225da8SJason M. Bills if (entryStart == std::string::npos) 1343cd225da8SJason M. Bills { 1344ac992cdeSJason M. Bills return LogParseError::parseFailed; 1345cd225da8SJason M. Bills } 1346cd225da8SJason M. Bills std::string_view entry(logEntry); 1347cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1348cd225da8SJason M. Bills // Use split to separate the entry into its fields 1349cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 135050ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1351cd225da8SJason M. Bills // We need at least a MessageId to be valid 13521e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 13531e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1354cd225da8SJason M. Bills { 1355ac992cdeSJason M. Bills return LogParseError::parseFailed; 1356cd225da8SJason M. Bills } 13571e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 13584851d45dSJason M. Bills // Get the Message from the MessageRegistry 1359fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1360c4bf6374SJason M. Bills 13611e6deaf6SEd Tanous logEntryIter++; 136254417b02SSui Chen if (message == nullptr) 1363c4bf6374SJason M. Bills { 136462598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1365ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1366c4bf6374SJason M. Bills } 1367c4bf6374SJason M. Bills 13681e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 13691e6deaf6SEd Tanous logEntryFields.end()); 1370c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1371c05bba45SEd Tanous 13721e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 13731e6deaf6SEd Tanous message->message); 13741e6deaf6SEd Tanous if (msg.empty()) 137515a86ff6SJason M. Bills { 13761e6deaf6SEd Tanous return LogParseError::parseFailed; 137715a86ff6SJason M. Bills } 13784851d45dSJason M. Bills 137995820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 138095820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 138195820184SJason M. Bills // between the '.' and the '+', so just remove them. 1382f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1383f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 138495820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1385c4bf6374SJason M. Bills { 138695820184SJason M. Bills timestamp.erase(dot, plus - dot); 1387c4bf6374SJason M. Bills } 1388c4bf6374SJason M. Bills 1389c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13909c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1391ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1392253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1393253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 139484afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 139584afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 139684afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 139784afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 139884afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 139984afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 140084afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 140184afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1402ac992cdeSJason M. Bills return LogParseError::success; 1403c4bf6374SJason M. Bills } 1404c4bf6374SJason M. Bills 1405*599b9af3SAlexander Hansen inline void handleSystemsLogServiceEventLogLogEntryCollection( 1406*599b9af3SAlexander Hansen App& app, const crow::Request& req, 140722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1408*599b9af3SAlexander Hansen const std::string& systemName) 1409*599b9af3SAlexander Hansen { 1410c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1411c937d2bfSEd Tanous .canDelegateTop = true, 1412c937d2bfSEd Tanous .canDelegateSkip = true, 1413c937d2bfSEd Tanous }; 1414c937d2bfSEd Tanous query_param::Query delegatedQuery; 1415*599b9af3SAlexander Hansen if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 1416*599b9af3SAlexander Hansen delegatedQuery, capabilities)) 1417c4bf6374SJason M. Bills { 1418c4bf6374SJason M. Bills return; 1419c4bf6374SJason M. Bills } 142025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 14217f3e84a1SEd Tanous { 14227f3e84a1SEd Tanous // Option currently returns no systems. TBD 14237f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 14247f3e84a1SEd Tanous systemName); 14257f3e84a1SEd Tanous return; 14267f3e84a1SEd Tanous } 1427253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 142822d268cbSEd Tanous { 142922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 143022d268cbSEd Tanous systemName); 143122d268cbSEd Tanous return; 143222d268cbSEd Tanous } 143322d268cbSEd Tanous 14345143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 14353648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 14363648c8beSEd Tanous 14377e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 14387e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1439c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1440c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1441c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1442253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1443253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1444c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1445c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1446c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1447cb92c03bSAndrew Geissler 14484978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1449c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 14507e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 14517e860f15SJohn Edward Broadbent // entry 145295820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 145395820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1454b01bf299SEd Tanous uint64_t entryCount = 0; 1455cd225da8SJason M. Bills std::string logEntry; 145695820184SJason M. Bills 14577e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14587e860f15SJohn Edward Broadbent // backwards 1459*599b9af3SAlexander Hansen for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++) 1460c4bf6374SJason M. Bills { 1461cd225da8SJason M. Bills std::ifstream logStream(*it); 146295820184SJason M. Bills if (!logStream.is_open()) 1463c4bf6374SJason M. Bills { 1464c4bf6374SJason M. Bills continue; 1465c4bf6374SJason M. Bills } 1466c4bf6374SJason M. Bills 1467e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1468e85d6b16SJason M. Bills bool firstEntry = true; 146995820184SJason M. Bills while (std::getline(logStream, logEntry)) 147095820184SJason M. Bills { 1471c4bf6374SJason M. Bills std::string idStr; 1472e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1473c4bf6374SJason M. Bills { 1474c4bf6374SJason M. Bills continue; 1475c4bf6374SJason M. Bills } 1476e85d6b16SJason M. Bills firstEntry = false; 1477e85d6b16SJason M. Bills 1478de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 147989492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 148089492a15SPatrick Williams bmcLogEntry); 1481ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1482ac992cdeSJason M. Bills { 1483ac992cdeSJason M. Bills continue; 1484ac992cdeSJason M. Bills } 1485ac992cdeSJason M. Bills if (status != LogParseError::success) 1486c4bf6374SJason M. Bills { 1487c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1488c4bf6374SJason M. Bills return; 1489c4bf6374SJason M. Bills } 1490de703c5dSJason M. Bills 1491de703c5dSJason M. Bills entryCount++; 1492de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1493de703c5dSJason M. Bills // start) and top (number of entries to display) 14943648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1495de703c5dSJason M. Bills { 1496de703c5dSJason M. Bills continue; 1497de703c5dSJason M. Bills } 1498de703c5dSJason M. Bills 1499b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1500c4bf6374SJason M. Bills } 150195820184SJason M. Bills } 1502c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 15033648c8beSEd Tanous if (skip + top < entryCount) 1504c4bf6374SJason M. Bills { 1505*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Members@odata.nextLink"] = 1506*599b9af3SAlexander Hansen boost::urls::format( 1507253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}", 1508253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top)); 1509c4bf6374SJason M. Bills } 1510897967deSJason M. Bills } 1511897967deSJason M. Bills 1512*599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogEntryCollection(App& app) 1513897967deSJason M. Bills { 1514*599b9af3SAlexander Hansen BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1515*599b9af3SAlexander Hansen .privileges(redfish::privileges::getLogEntryCollection) 1516*599b9af3SAlexander Hansen .methods(boost::beast::http::verb::get)(std::bind_front( 1517*599b9af3SAlexander Hansen handleSystemsLogServiceEventLogLogEntryCollection, std::ref(app))); 1518*599b9af3SAlexander Hansen } 1519*599b9af3SAlexander Hansen 1520*599b9af3SAlexander Hansen inline void handleSystemsLogServiceEventLogEntriesGet( 1521*599b9af3SAlexander Hansen App& app, const crow::Request& req, 15227e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1523*599b9af3SAlexander Hansen const std::string& systemName, const std::string& param) 1524*599b9af3SAlexander Hansen { 15253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 152645ca1b86SEd Tanous { 152745ca1b86SEd Tanous return; 152845ca1b86SEd Tanous } 152925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 15307f3e84a1SEd Tanous { 15317f3e84a1SEd Tanous // Option currently returns no systems. TBD 15327f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15337f3e84a1SEd Tanous systemName); 15347f3e84a1SEd Tanous return; 15357f3e84a1SEd Tanous } 153622d268cbSEd Tanous 1537253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 153822d268cbSEd Tanous { 153922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 154022d268cbSEd Tanous systemName); 154122d268cbSEd Tanous return; 154222d268cbSEd Tanous } 154322d268cbSEd Tanous 15447e860f15SJohn Edward Broadbent const std::string& targetID = param; 15458d1b46d7Szhanghch05 15467e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 15477e860f15SJohn Edward Broadbent // entry to find the target entry 1548897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1549897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1550897967deSJason M. Bills std::string logEntry; 1551897967deSJason M. Bills 15527e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15537e860f15SJohn Edward Broadbent // backwards 1554*599b9af3SAlexander Hansen for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++) 1555897967deSJason M. Bills { 1556897967deSJason M. Bills std::ifstream logStream(*it); 1557897967deSJason M. Bills if (!logStream.is_open()) 1558897967deSJason M. Bills { 1559897967deSJason M. Bills continue; 1560897967deSJason M. Bills } 1561897967deSJason M. Bills 1562897967deSJason M. Bills // Reset the unique ID on the first entry 1563897967deSJason M. Bills bool firstEntry = true; 1564897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1565897967deSJason M. Bills { 1566897967deSJason M. Bills std::string idStr; 1567897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1568897967deSJason M. Bills { 1569897967deSJason M. Bills continue; 1570897967deSJason M. Bills } 1571897967deSJason M. Bills firstEntry = false; 1572897967deSJason M. Bills 1573897967deSJason M. Bills if (idStr == targetID) 1574897967deSJason M. Bills { 1575de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1576*599b9af3SAlexander Hansen LogParseError status = fillEventLogEntryJson(idStr, logEntry, 1577*599b9af3SAlexander Hansen bmcLogEntry); 1578ac992cdeSJason M. Bills if (status != LogParseError::success) 1579897967deSJason M. Bills { 1580897967deSJason M. Bills messages::internalError(asyncResp->res); 1581897967deSJason M. Bills return; 1582897967deSJason M. Bills } 1583d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1584897967deSJason M. Bills return; 1585897967deSJason M. Bills } 1586897967deSJason M. Bills } 1587897967deSJason M. Bills } 1588897967deSJason M. Bills // Requested ID was not found 15899db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 1590*599b9af3SAlexander Hansen } 1591*599b9af3SAlexander Hansen 1592*599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogEntry(App& app) 1593*599b9af3SAlexander Hansen { 1594*599b9af3SAlexander Hansen BMCWEB_ROUTE( 1595*599b9af3SAlexander Hansen app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1596*599b9af3SAlexander Hansen .privileges(redfish::privileges::getLogEntry) 1597*599b9af3SAlexander Hansen .methods(boost::beast::http::verb::get)(std::bind_front( 1598*599b9af3SAlexander Hansen handleSystemsLogServiceEventLogEntriesGet, std::ref(app))); 1599*599b9af3SAlexander Hansen } 1600*599b9af3SAlexander Hansen 1601*599b9af3SAlexander Hansen inline void dBusEventLogEntryCollection( 1602*599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1603*599b9af3SAlexander Hansen { 1604*599b9af3SAlexander Hansen // Collections don't include the static data added by SubRoute 1605*599b9af3SAlexander Hansen // because it has a duplicate entry for members 1606*599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.type"] = 1607*599b9af3SAlexander Hansen "#LogEntryCollection.LogEntryCollection"; 1608*599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.id"] = 1609*599b9af3SAlexander Hansen std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1610*599b9af3SAlexander Hansen BMCWEB_REDFISH_SYSTEM_URI_NAME); 1611*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1612*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Description"] = 1613*599b9af3SAlexander Hansen "Collection of System Event Log Entries"; 1614*599b9af3SAlexander Hansen 1615*599b9af3SAlexander Hansen // DBus implementation of EventLog/Entries 1616*599b9af3SAlexander Hansen // Make call to Logging Service to find all log entry objects 1617*599b9af3SAlexander Hansen sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 1618*599b9af3SAlexander Hansen dbus::utility::getManagedObjects( 1619*599b9af3SAlexander Hansen "xyz.openbmc_project.Logging", path, 1620*599b9af3SAlexander Hansen [asyncResp](const boost::system::error_code& ec, 1621*599b9af3SAlexander Hansen const dbus::utility::ManagedObjectType& resp) { 1622*599b9af3SAlexander Hansen if (ec) 1623*599b9af3SAlexander Hansen { 1624*599b9af3SAlexander Hansen // TODO Handle for specific error code 1625*599b9af3SAlexander Hansen BMCWEB_LOG_ERROR("getLogEntriesIfaceData resp_handler got error {}", 1626*599b9af3SAlexander Hansen ec); 1627*599b9af3SAlexander Hansen messages::internalError(asyncResp->res); 1628*599b9af3SAlexander Hansen return; 1629*599b9af3SAlexander Hansen } 1630*599b9af3SAlexander Hansen nlohmann::json::array_t entriesArray; 1631*599b9af3SAlexander Hansen for (const auto& objectPath : resp) 1632*599b9af3SAlexander Hansen { 1633*599b9af3SAlexander Hansen const uint32_t* id = nullptr; 1634*599b9af3SAlexander Hansen const uint64_t* timestamp = nullptr; 1635*599b9af3SAlexander Hansen const uint64_t* updateTimestamp = nullptr; 1636*599b9af3SAlexander Hansen const std::string* severity = nullptr; 1637*599b9af3SAlexander Hansen const std::string* message = nullptr; 1638*599b9af3SAlexander Hansen const std::string* filePath = nullptr; 1639*599b9af3SAlexander Hansen const std::string* resolution = nullptr; 1640*599b9af3SAlexander Hansen bool resolved = false; 1641*599b9af3SAlexander Hansen const std::string* notify = nullptr; 1642*599b9af3SAlexander Hansen 1643*599b9af3SAlexander Hansen for (const auto& interfaceMap : objectPath.second) 1644*599b9af3SAlexander Hansen { 1645*599b9af3SAlexander Hansen if (interfaceMap.first == "xyz.openbmc_project.Logging.Entry") 1646*599b9af3SAlexander Hansen { 1647*599b9af3SAlexander Hansen for (const auto& propertyMap : interfaceMap.second) 1648*599b9af3SAlexander Hansen { 1649*599b9af3SAlexander Hansen if (propertyMap.first == "Id") 1650*599b9af3SAlexander Hansen { 1651*599b9af3SAlexander Hansen id = std::get_if<uint32_t>(&propertyMap.second); 1652*599b9af3SAlexander Hansen } 1653*599b9af3SAlexander Hansen else if (propertyMap.first == "Timestamp") 1654*599b9af3SAlexander Hansen { 1655*599b9af3SAlexander Hansen timestamp = 1656*599b9af3SAlexander Hansen std::get_if<uint64_t>(&propertyMap.second); 1657*599b9af3SAlexander Hansen } 1658*599b9af3SAlexander Hansen else if (propertyMap.first == "UpdateTimestamp") 1659*599b9af3SAlexander Hansen { 1660*599b9af3SAlexander Hansen updateTimestamp = 1661*599b9af3SAlexander Hansen std::get_if<uint64_t>(&propertyMap.second); 1662*599b9af3SAlexander Hansen } 1663*599b9af3SAlexander Hansen else if (propertyMap.first == "Severity") 1664*599b9af3SAlexander Hansen { 1665*599b9af3SAlexander Hansen severity = 1666*599b9af3SAlexander Hansen std::get_if<std::string>(&propertyMap.second); 1667*599b9af3SAlexander Hansen } 1668*599b9af3SAlexander Hansen else if (propertyMap.first == "Resolution") 1669*599b9af3SAlexander Hansen { 1670*599b9af3SAlexander Hansen resolution = 1671*599b9af3SAlexander Hansen std::get_if<std::string>(&propertyMap.second); 1672*599b9af3SAlexander Hansen } 1673*599b9af3SAlexander Hansen else if (propertyMap.first == "Message") 1674*599b9af3SAlexander Hansen { 1675*599b9af3SAlexander Hansen message = 1676*599b9af3SAlexander Hansen std::get_if<std::string>(&propertyMap.second); 1677*599b9af3SAlexander Hansen } 1678*599b9af3SAlexander Hansen else if (propertyMap.first == "Resolved") 1679*599b9af3SAlexander Hansen { 1680*599b9af3SAlexander Hansen const bool* resolveptr = 1681*599b9af3SAlexander Hansen std::get_if<bool>(&propertyMap.second); 1682*599b9af3SAlexander Hansen if (resolveptr == nullptr) 1683*599b9af3SAlexander Hansen { 1684*599b9af3SAlexander Hansen messages::internalError(asyncResp->res); 1685*599b9af3SAlexander Hansen return; 1686*599b9af3SAlexander Hansen } 1687*599b9af3SAlexander Hansen resolved = *resolveptr; 1688*599b9af3SAlexander Hansen } 1689*599b9af3SAlexander Hansen else if (propertyMap.first == "ServiceProviderNotify") 1690*599b9af3SAlexander Hansen { 1691*599b9af3SAlexander Hansen notify = 1692*599b9af3SAlexander Hansen std::get_if<std::string>(&propertyMap.second); 1693*599b9af3SAlexander Hansen if (notify == nullptr) 1694*599b9af3SAlexander Hansen { 1695*599b9af3SAlexander Hansen messages::internalError(asyncResp->res); 1696*599b9af3SAlexander Hansen return; 1697*599b9af3SAlexander Hansen } 1698*599b9af3SAlexander Hansen } 1699*599b9af3SAlexander Hansen } 1700*599b9af3SAlexander Hansen if (id == nullptr || message == nullptr || 1701*599b9af3SAlexander Hansen severity == nullptr) 1702*599b9af3SAlexander Hansen { 1703*599b9af3SAlexander Hansen messages::internalError(asyncResp->res); 1704*599b9af3SAlexander Hansen return; 1705*599b9af3SAlexander Hansen } 1706*599b9af3SAlexander Hansen } 1707*599b9af3SAlexander Hansen else if (interfaceMap.first == 1708*599b9af3SAlexander Hansen "xyz.openbmc_project.Common.FilePath") 1709*599b9af3SAlexander Hansen { 1710*599b9af3SAlexander Hansen for (const auto& propertyMap : interfaceMap.second) 1711*599b9af3SAlexander Hansen { 1712*599b9af3SAlexander Hansen if (propertyMap.first == "Path") 1713*599b9af3SAlexander Hansen { 1714*599b9af3SAlexander Hansen filePath = 1715*599b9af3SAlexander Hansen std::get_if<std::string>(&propertyMap.second); 1716*599b9af3SAlexander Hansen } 1717*599b9af3SAlexander Hansen } 1718*599b9af3SAlexander Hansen } 1719*599b9af3SAlexander Hansen } 1720*599b9af3SAlexander Hansen // Object path without the 1721*599b9af3SAlexander Hansen // xyz.openbmc_project.Logging.Entry interface, ignore 1722*599b9af3SAlexander Hansen // and continue. 1723*599b9af3SAlexander Hansen if (id == nullptr || message == nullptr || severity == nullptr || 1724*599b9af3SAlexander Hansen timestamp == nullptr || updateTimestamp == nullptr) 1725*599b9af3SAlexander Hansen { 1726*599b9af3SAlexander Hansen continue; 1727*599b9af3SAlexander Hansen } 1728*599b9af3SAlexander Hansen nlohmann::json& thisEntry = entriesArray.emplace_back(); 1729*599b9af3SAlexander Hansen thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1730*599b9af3SAlexander Hansen thisEntry["@odata.id"] = boost::urls::format( 1731*599b9af3SAlexander Hansen "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1732*599b9af3SAlexander Hansen BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 1733*599b9af3SAlexander Hansen thisEntry["Name"] = "System Event Log Entry"; 1734*599b9af3SAlexander Hansen thisEntry["Id"] = std::to_string(*id); 1735*599b9af3SAlexander Hansen thisEntry["Message"] = *message; 1736*599b9af3SAlexander Hansen thisEntry["Resolved"] = resolved; 1737*599b9af3SAlexander Hansen if ((resolution != nullptr) && (!(*resolution).empty())) 1738*599b9af3SAlexander Hansen { 1739*599b9af3SAlexander Hansen thisEntry["Resolution"] = *resolution; 1740*599b9af3SAlexander Hansen } 1741*599b9af3SAlexander Hansen if (notify != nullptr) 1742*599b9af3SAlexander Hansen { 1743*599b9af3SAlexander Hansen std::optional<bool> notifyAction = 1744*599b9af3SAlexander Hansen getProviderNotifyAction(*notify); 1745*599b9af3SAlexander Hansen if (notifyAction) 1746*599b9af3SAlexander Hansen { 1747*599b9af3SAlexander Hansen thisEntry["ServiceProviderNotified"] = *notifyAction; 1748*599b9af3SAlexander Hansen } 1749*599b9af3SAlexander Hansen } 1750*599b9af3SAlexander Hansen thisEntry["EntryType"] = "Event"; 1751*599b9af3SAlexander Hansen thisEntry["Severity"] = translateSeverityDbusToRedfish(*severity); 1752*599b9af3SAlexander Hansen thisEntry["Created"] = 1753*599b9af3SAlexander Hansen redfish::time_utils::getDateTimeUintMs(*timestamp); 1754*599b9af3SAlexander Hansen thisEntry["Modified"] = 1755*599b9af3SAlexander Hansen redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1756*599b9af3SAlexander Hansen if (filePath != nullptr) 1757*599b9af3SAlexander Hansen { 1758*599b9af3SAlexander Hansen thisEntry["AdditionalDataURI"] = 1759*599b9af3SAlexander Hansen std::format( 1760*599b9af3SAlexander Hansen "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 1761*599b9af3SAlexander Hansen BMCWEB_REDFISH_SYSTEM_URI_NAME) + 1762*599b9af3SAlexander Hansen std::to_string(*id) + "/attachment"; 1763*599b9af3SAlexander Hansen } 1764*599b9af3SAlexander Hansen } 1765*599b9af3SAlexander Hansen std::ranges::sort(entriesArray, [](const nlohmann::json& left, 1766*599b9af3SAlexander Hansen const nlohmann::json& right) { 1767*599b9af3SAlexander Hansen return (left["Id"] <= right["Id"]); 1768*599b9af3SAlexander Hansen }); 1769*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 1770*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 17717e860f15SJohn Edward Broadbent }); 177208a4e4b5SAnthony Wilson } 177308a4e4b5SAnthony Wilson 17747e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 177508a4e4b5SAnthony Wilson { 177622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1777ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1778002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1779002d39b4SEd Tanous [&app](const crow::Request& req, 178022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 178122d268cbSEd Tanous const std::string& systemName) { 17823ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 178345ca1b86SEd Tanous { 178445ca1b86SEd Tanous return; 178545ca1b86SEd Tanous } 178625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 17877f3e84a1SEd Tanous { 17887f3e84a1SEd Tanous // Option currently returns no systems. TBD 17897f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17907f3e84a1SEd Tanous systemName); 17917f3e84a1SEd Tanous return; 17927f3e84a1SEd Tanous } 1793253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 179422d268cbSEd Tanous { 179522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 179622d268cbSEd Tanous systemName); 179722d268cbSEd Tanous return; 179822d268cbSEd Tanous } 1799*599b9af3SAlexander Hansen dBusEventLogEntryCollection(asyncResp); 1800*599b9af3SAlexander Hansen }); 1801*599b9af3SAlexander Hansen } 180222d268cbSEd Tanous 1803*599b9af3SAlexander Hansen inline void 1804*599b9af3SAlexander Hansen dBusEventLogEntryGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1805*599b9af3SAlexander Hansen std::string& entryID) 1806*599b9af3SAlexander Hansen { 1807*599b9af3SAlexander Hansen dbus::utility::escapePathForDbus(entryID); 180808a4e4b5SAnthony Wilson 1809cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1810cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1811*599b9af3SAlexander Hansen sdbusplus::asio::getAllProperties( 1812*599b9af3SAlexander Hansen *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1813*599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryID, "", 1814*599b9af3SAlexander Hansen [asyncResp, entryID](const boost::system::error_code& ec, 1815*599b9af3SAlexander Hansen const dbus::utility::DBusPropertiesMap& resp) { 1816*599b9af3SAlexander Hansen if (ec.value() == EBADR) 1817*599b9af3SAlexander Hansen { 1818*599b9af3SAlexander Hansen messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1819*599b9af3SAlexander Hansen entryID); 1820*599b9af3SAlexander Hansen return; 1821*599b9af3SAlexander Hansen } 1822cb92c03bSAndrew Geissler if (ec) 1823cb92c03bSAndrew Geissler { 1824*599b9af3SAlexander Hansen BMCWEB_LOG_ERROR("EventLogEntry (DBus) resp_handler got error {}", 1825*599b9af3SAlexander Hansen ec); 1826cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1827cb92c03bSAndrew Geissler return; 1828cb92c03bSAndrew Geissler } 1829914e2d5dSEd Tanous const uint32_t* id = nullptr; 1830c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1831c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1832914e2d5dSEd Tanous const std::string* severity = nullptr; 1833914e2d5dSEd Tanous const std::string* message = nullptr; 1834914e2d5dSEd Tanous const std::string* filePath = nullptr; 18359c11a172SVijay Lobo const std::string* resolution = nullptr; 183675710de2SXiaochao Ma bool resolved = false; 18379017faf2SAbhishek Patel const std::string* notify = nullptr; 18389017faf2SAbhishek Patel 1839*599b9af3SAlexander Hansen const bool success = sdbusplus::unpackPropertiesNoThrow( 1840*599b9af3SAlexander Hansen dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1841*599b9af3SAlexander Hansen timestamp, "UpdateTimestamp", updateTimestamp, "Severity", severity, 1842*599b9af3SAlexander Hansen "Message", message, "Resolved", resolved, "Resolution", resolution, 1843*599b9af3SAlexander Hansen "Path", filePath, "ServiceProviderNotify", notify); 1844*599b9af3SAlexander Hansen 1845*599b9af3SAlexander Hansen if (!success) 18467e860f15SJohn Edward Broadbent { 1847002d39b4SEd Tanous messages::internalError(asyncResp->res); 18487e860f15SJohn Edward Broadbent return; 18497e860f15SJohn Edward Broadbent } 1850*599b9af3SAlexander Hansen 1851*599b9af3SAlexander Hansen if (id == nullptr || message == nullptr || severity == nullptr || 1852*599b9af3SAlexander Hansen timestamp == nullptr || updateTimestamp == nullptr || 1853*599b9af3SAlexander Hansen notify == nullptr) 18549017faf2SAbhishek Patel { 18559017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18569017faf2SAbhishek Patel return; 18579017faf2SAbhishek Patel } 1858*599b9af3SAlexander Hansen 1859*599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1860*599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1861253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1862253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 1863*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1864*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1865*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Message"] = *message; 1866*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Resolved"] = resolved; 1867*599b9af3SAlexander Hansen std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 18689017faf2SAbhishek Patel if (notifyAction) 18699017faf2SAbhishek Patel { 1870*599b9af3SAlexander Hansen asyncResp->res.jsonValue["ServiceProviderNotified"] = *notifyAction; 18719017faf2SAbhishek Patel } 1872*599b9af3SAlexander Hansen if ((resolution != nullptr) && (!(*resolution).empty())) 1873*599b9af3SAlexander Hansen { 1874*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Resolution"] = *resolution; 1875b0b6152cSEd Tanous } 1876*599b9af3SAlexander Hansen asyncResp->res.jsonValue["EntryType"] = "Event"; 1877*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Severity"] = 18787e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 1879*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Created"] = 18802b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1881*599b9af3SAlexander Hansen asyncResp->res.jsonValue["Modified"] = 18822b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 18837e860f15SJohn Edward Broadbent if (filePath != nullptr) 18847e860f15SJohn Edward Broadbent { 1885*599b9af3SAlexander Hansen asyncResp->res.jsonValue["AdditionalDataURI"] = 1886253f11b8SEd Tanous std::format( 1887253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 1888253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 18897e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 18907e860f15SJohn Edward Broadbent } 1891*599b9af3SAlexander Hansen }); 18927e860f15SJohn Edward Broadbent } 1893*599b9af3SAlexander Hansen 1894*599b9af3SAlexander Hansen inline void 1895*599b9af3SAlexander Hansen dBusEventLogEntryPatch(const crow::Request& req, 1896*599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1897*599b9af3SAlexander Hansen const std::string& entryId) 1898*599b9af3SAlexander Hansen { 1899*599b9af3SAlexander Hansen std::optional<bool> resolved; 1900*599b9af3SAlexander Hansen 1901*599b9af3SAlexander Hansen if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", resolved)) 1902*599b9af3SAlexander Hansen { 1903*599b9af3SAlexander Hansen return; 1904*599b9af3SAlexander Hansen } 1905*599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Set Resolved"); 1906*599b9af3SAlexander Hansen 1907*599b9af3SAlexander Hansen setDbusProperty(asyncResp, "Resolved", "xyz.openbmc_project.Logging", 1908*599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryId, 1909*599b9af3SAlexander Hansen "xyz.openbmc_project.Logging.Entry", "Resolved", 1910*599b9af3SAlexander Hansen resolved.value_or(false)); 1911*599b9af3SAlexander Hansen } 1912*599b9af3SAlexander Hansen 1913*599b9af3SAlexander Hansen inline void 1914*599b9af3SAlexander Hansen dBusEventLogEntryDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1915*599b9af3SAlexander Hansen std::string entryID) 1916*599b9af3SAlexander Hansen { 1917*599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Do delete single event entries."); 1918*599b9af3SAlexander Hansen 1919*599b9af3SAlexander Hansen dbus::utility::escapePathForDbus(entryID); 1920*599b9af3SAlexander Hansen 1921*599b9af3SAlexander Hansen // Process response from Logging service. 1922*599b9af3SAlexander Hansen auto respHandler = [asyncResp, 1923*599b9af3SAlexander Hansen entryID](const boost::system::error_code& ec) { 1924*599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 1925*599b9af3SAlexander Hansen if (ec) 1926*599b9af3SAlexander Hansen { 1927*599b9af3SAlexander Hansen if (ec.value() == EBADR) 1928*599b9af3SAlexander Hansen { 1929*599b9af3SAlexander Hansen messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 1930*599b9af3SAlexander Hansen return; 1931*599b9af3SAlexander Hansen } 1932*599b9af3SAlexander Hansen // TODO Handle for specific error code 1933*599b9af3SAlexander Hansen BMCWEB_LOG_ERROR( 1934*599b9af3SAlexander Hansen "EventLogEntry (DBus) doDelete respHandler got error {}", ec); 1935*599b9af3SAlexander Hansen asyncResp->res.result( 1936*599b9af3SAlexander Hansen boost::beast::http::status::internal_server_error); 1937*599b9af3SAlexander Hansen return; 1938*599b9af3SAlexander Hansen } 1939*599b9af3SAlexander Hansen 1940*599b9af3SAlexander Hansen asyncResp->res.result(boost::beast::http::status::ok); 1941*599b9af3SAlexander Hansen }; 1942*599b9af3SAlexander Hansen 1943*599b9af3SAlexander Hansen // Make call to Logging service to request Delete Log 1944*599b9af3SAlexander Hansen crow::connections::systemBus->async_method_call( 1945*599b9af3SAlexander Hansen respHandler, "xyz.openbmc_project.Logging", 1946*599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryID, 1947*599b9af3SAlexander Hansen "xyz.openbmc_project.Object.Delete", "Delete"); 19487e860f15SJohn Edward Broadbent } 19497e860f15SJohn Edward Broadbent 19507e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 19517e860f15SJohn Edward Broadbent { 19527e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 195322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1954ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1955002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1956002d39b4SEd Tanous [&app](const crow::Request& req, 19577e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 195822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19607e860f15SJohn Edward Broadbent { 196145ca1b86SEd Tanous return; 196245ca1b86SEd Tanous } 196325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19647f3e84a1SEd Tanous { 19657f3e84a1SEd Tanous // Option currently returns no systems. TBD 19667f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19677f3e84a1SEd Tanous systemName); 19687f3e84a1SEd Tanous return; 19697f3e84a1SEd Tanous } 1970253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 197122d268cbSEd Tanous { 197222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 197322d268cbSEd Tanous systemName); 197422d268cbSEd Tanous return; 197522d268cbSEd Tanous } 197622d268cbSEd Tanous 19777e860f15SJohn Edward Broadbent std::string entryID = param; 19787e860f15SJohn Edward Broadbent 1979*599b9af3SAlexander Hansen dBusEventLogEntryGet(asyncResp, entryID); 19807e860f15SJohn Edward Broadbent }); 1981336e96c6SChicago Duan 19827e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 198322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1984ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 19857e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 198645ca1b86SEd Tanous [&app](const crow::Request& req, 19877e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 198822d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 19893ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 199045ca1b86SEd Tanous { 199145ca1b86SEd Tanous return; 199245ca1b86SEd Tanous } 199325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19947f3e84a1SEd Tanous { 19957f3e84a1SEd Tanous // Option currently returns no systems. TBD 19967f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19977f3e84a1SEd Tanous systemName); 19987f3e84a1SEd Tanous return; 19997f3e84a1SEd Tanous } 2000253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 200122d268cbSEd Tanous { 200222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 200322d268cbSEd Tanous systemName); 200422d268cbSEd Tanous return; 200522d268cbSEd Tanous } 200675710de2SXiaochao Ma 2007*599b9af3SAlexander Hansen dBusEventLogEntryPatch(req, asyncResp, entryId); 20087e860f15SJohn Edward Broadbent }); 200975710de2SXiaochao Ma 20107e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 201122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2012ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2013ed398213SEd Tanous 2014002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2015002d39b4SEd Tanous [&app](const crow::Request& req, 2016002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 201722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 20183ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2019336e96c6SChicago Duan { 202045ca1b86SEd Tanous return; 202145ca1b86SEd Tanous } 202225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20237f3e84a1SEd Tanous { 20247f3e84a1SEd Tanous // Option currently returns no systems. TBD 20257f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20267f3e84a1SEd Tanous systemName); 20277f3e84a1SEd Tanous return; 20287f3e84a1SEd Tanous } 2029253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 203022d268cbSEd Tanous { 203122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 203222d268cbSEd Tanous systemName); 203322d268cbSEd Tanous return; 203422d268cbSEd Tanous } 2035*599b9af3SAlexander Hansen dBusEventLogEntryDelete(asyncResp, param); 20367e860f15SJohn Edward Broadbent }); 2037400fd1fbSAdriana Kobylak } 2038400fd1fbSAdriana Kobylak 2039b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2040b7028ebfSSpencer Ku 2041b7028ebfSSpencer Ku inline bool 2042b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2043b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2044b7028ebfSSpencer Ku { 2045b7028ebfSSpencer Ku std::error_code ec; 2046b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2047b7028ebfSSpencer Ku if (ec) 2048b7028ebfSSpencer Ku { 2049bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2050b7028ebfSSpencer Ku return false; 2051b7028ebfSSpencer Ku } 2052b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2053b7028ebfSSpencer Ku { 2054b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2055b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2056b7028ebfSSpencer Ku // path 205711ba3979SEd Tanous if (filename.starts_with("log")) 2058b7028ebfSSpencer Ku { 2059b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2060b7028ebfSSpencer Ku } 2061b7028ebfSSpencer Ku } 2062b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2063b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2064b7028ebfSSpencer Ku // descending order. 2065b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2066b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2067b7028ebfSSpencer Ku 2068b7028ebfSSpencer Ku return true; 2069b7028ebfSSpencer Ku } 2070b7028ebfSSpencer Ku 207102cad96eSEd Tanous inline bool getHostLoggerEntries( 207202cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 207302cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2074b7028ebfSSpencer Ku { 2075b7028ebfSSpencer Ku GzFileReader logFile; 2076b7028ebfSSpencer Ku 2077b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2078b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2079b7028ebfSSpencer Ku { 2080b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2081b7028ebfSSpencer Ku { 208262598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2083b7028ebfSSpencer Ku return false; 2084b7028ebfSSpencer Ku } 2085b7028ebfSSpencer Ku } 2086b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2087b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2088b7028ebfSSpencer Ku if (!lastMessage.empty()) 2089b7028ebfSSpencer Ku { 2090b7028ebfSSpencer Ku logCount++; 2091b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2092b7028ebfSSpencer Ku { 2093b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2094b7028ebfSSpencer Ku } 2095b7028ebfSSpencer Ku } 2096b7028ebfSSpencer Ku return true; 2097b7028ebfSSpencer Ku } 2098b7028ebfSSpencer Ku 20996f056f24SEd Tanous inline void fillHostLoggerEntryJson(std::string_view logEntryID, 21006f056f24SEd Tanous std::string_view msg, 21016d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2102b7028ebfSSpencer Ku { 2103b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 21049c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2105ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2106253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}", 2107253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 21086d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 21096d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 21106d6574c9SJason M. Bills logEntryJson["Message"] = msg; 2111539d8c6bSEd Tanous logEntryJson["EntryType"] = log_entry::LogEntryType::Oem; 2112539d8c6bSEd Tanous logEntryJson["Severity"] = log_entry::EventSeverity::OK; 21136d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2114b7028ebfSSpencer Ku } 2115b7028ebfSSpencer Ku 2116b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2117b7028ebfSSpencer Ku { 211822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2119b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 21201476687dSEd Tanous .methods(boost::beast::http::verb::get)( 21211476687dSEd Tanous [&app](const crow::Request& req, 212222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 212322d268cbSEd Tanous const std::string& systemName) { 21243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 212545ca1b86SEd Tanous { 212645ca1b86SEd Tanous return; 212745ca1b86SEd Tanous } 212825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 21297f3e84a1SEd Tanous { 21307f3e84a1SEd Tanous // Option currently returns no systems. TBD 21317f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21327f3e84a1SEd Tanous systemName); 21337f3e84a1SEd Tanous return; 21347f3e84a1SEd Tanous } 2135253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 213622d268cbSEd Tanous { 213722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 213822d268cbSEd Tanous systemName); 213922d268cbSEd Tanous return; 214022d268cbSEd Tanous } 2141b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2142253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 2143253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2144b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2145b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2146b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2147b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2148b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21491476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 2150253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2151253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2152b7028ebfSSpencer Ku }); 2153b7028ebfSSpencer Ku } 2154b7028ebfSSpencer Ku 2155b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2156b7028ebfSSpencer Ku { 2157b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 215822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2159b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2160002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2161002d39b4SEd Tanous [&app](const crow::Request& req, 216222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 216322d268cbSEd Tanous const std::string& systemName) { 2164c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2165c937d2bfSEd Tanous .canDelegateTop = true, 2166c937d2bfSEd Tanous .canDelegateSkip = true, 2167c937d2bfSEd Tanous }; 2168c937d2bfSEd Tanous query_param::Query delegatedQuery; 2169c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21703ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2171b7028ebfSSpencer Ku { 2172b7028ebfSSpencer Ku return; 2173b7028ebfSSpencer Ku } 217425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 21757f3e84a1SEd Tanous { 21767f3e84a1SEd Tanous // Option currently returns no systems. TBD 21777f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21787f3e84a1SEd Tanous systemName); 21797f3e84a1SEd Tanous return; 21807f3e84a1SEd Tanous } 2181253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 218222d268cbSEd Tanous { 218322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 218422d268cbSEd Tanous systemName); 218522d268cbSEd Tanous return; 218622d268cbSEd Tanous } 2187b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2188253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2189253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2190b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2191b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2192b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2193b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2194b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21950fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2196b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2197b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2198b7028ebfSSpencer Ku 2199b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2200b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2201b7028ebfSSpencer Ku { 2202bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2203b7028ebfSSpencer Ku return; 2204b7028ebfSSpencer Ku } 22053648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 22063648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 22075143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2208b7028ebfSSpencer Ku size_t logCount = 0; 2209b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2210b7028ebfSSpencer Ku // control by skip and top. 2211b7028ebfSSpencer Ku std::vector<std::string> logEntries; 22123648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 22133648c8beSEd Tanous logCount)) 2214b7028ebfSSpencer Ku { 2215b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2216b7028ebfSSpencer Ku return; 2217b7028ebfSSpencer Ku } 2218b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2219b7028ebfSSpencer Ku // log count 222026f6976fSEd Tanous if (logEntries.empty()) 2221b7028ebfSSpencer Ku { 2222b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2223b7028ebfSSpencer Ku return; 2224b7028ebfSSpencer Ku } 222526f6976fSEd Tanous if (!logEntries.empty()) 2226b7028ebfSSpencer Ku { 2227b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2228b7028ebfSSpencer Ku { 22296d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22303648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 22313648c8beSEd Tanous hostLogEntry); 2232b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2233b7028ebfSSpencer Ku } 2234b7028ebfSSpencer Ku 2235b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 22363648c8beSEd Tanous if (skip + top < logCount) 2237b7028ebfSSpencer Ku { 2238b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 2239253f11b8SEd Tanous std::format( 2240253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=", 2241253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 22423648c8beSEd Tanous std::to_string(skip + top); 2243b7028ebfSSpencer Ku } 2244b7028ebfSSpencer Ku } 2245b7028ebfSSpencer Ku }); 2246b7028ebfSSpencer Ku } 2247b7028ebfSSpencer Ku 2248b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2249b7028ebfSSpencer Ku { 2250b7028ebfSSpencer Ku BMCWEB_ROUTE( 225122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2252b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2253b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 225445ca1b86SEd Tanous [&app](const crow::Request& req, 2255b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 225622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 225845ca1b86SEd Tanous { 225945ca1b86SEd Tanous return; 226045ca1b86SEd Tanous } 226125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 22627f3e84a1SEd Tanous { 22637f3e84a1SEd Tanous // Option currently returns no systems. TBD 22647f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22657f3e84a1SEd Tanous systemName); 22667f3e84a1SEd Tanous return; 22677f3e84a1SEd Tanous } 2268253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 226922d268cbSEd Tanous { 227022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 227122d268cbSEd Tanous systemName); 227222d268cbSEd Tanous return; 227322d268cbSEd Tanous } 22746f056f24SEd Tanous std::string_view targetID = param; 2275b7028ebfSSpencer Ku 2276b7028ebfSSpencer Ku uint64_t idInt = 0; 2277ca45aa3cSEd Tanous 22786f056f24SEd Tanous auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(), 227984396af9SPatrick Williams idInt); 22806f056f24SEd Tanous if (ec != std::errc{} || ptr != targetID.end()) 2281b7028ebfSSpencer Ku { 22829db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2283b7028ebfSSpencer Ku return; 2284b7028ebfSSpencer Ku } 2285b7028ebfSSpencer Ku 2286b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2287b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2288b7028ebfSSpencer Ku { 2289bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2290b7028ebfSSpencer Ku return; 2291b7028ebfSSpencer Ku } 2292b7028ebfSSpencer Ku 2293b7028ebfSSpencer Ku size_t logCount = 0; 22943648c8beSEd Tanous size_t top = 1; 2295b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2296b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2297b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2298b7028ebfSSpencer Ku // get that entry 2299002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2300002d39b4SEd Tanous logCount)) 2301b7028ebfSSpencer Ku { 2302b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2303b7028ebfSSpencer Ku return; 2304b7028ebfSSpencer Ku } 2305b7028ebfSSpencer Ku 2306b7028ebfSSpencer Ku if (!logEntries.empty()) 2307b7028ebfSSpencer Ku { 23086d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23096d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 23106d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2311b7028ebfSSpencer Ku return; 2312b7028ebfSSpencer Ku } 2313b7028ebfSSpencer Ku 2314b7028ebfSSpencer Ku // Requested ID was not found 23159db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2316b7028ebfSSpencer Ku }); 2317b7028ebfSSpencer Ku } 2318b7028ebfSSpencer Ku 2319dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2320fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2321253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2322253f11b8SEd Tanous const std::string& managerId) 23231da66f75SEd Tanous { 23243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 232545ca1b86SEd Tanous { 232645ca1b86SEd Tanous return; 232745ca1b86SEd Tanous } 2328253f11b8SEd Tanous 2329253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2330253f11b8SEd Tanous { 2331253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2332253f11b8SEd Tanous return; 2333253f11b8SEd Tanous } 2334253f11b8SEd Tanous 23357e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 23367e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2337e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 23381da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2339253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2340253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME); 2341002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2342e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 23431da66f75SEd Tanous "Collection of LogServices for this Manager"; 2344002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2345c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2346fdd26906SClaire Weinan 234725b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_BMC_JOURNAL) 234825b54dbaSEd Tanous { 2349613dabeaSEd Tanous nlohmann::json::object_t journal; 2350253f11b8SEd Tanous journal["@odata.id"] = 2351253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal", 2352253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2353b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 235425b54dbaSEd Tanous } 2355fdd26906SClaire Weinan 2356fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2357fdd26906SClaire Weinan 235825b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 235925b54dbaSEd Tanous { 236015912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 23617a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 23627a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 23637a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 236425b54dbaSEd Tanous [asyncResp](const boost::system::error_code& ec, 236525b54dbaSEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 236625b54dbaSEd Tanous subTreePaths) { 2367fdd26906SClaire Weinan if (ec) 2368fdd26906SClaire Weinan { 236962598e31SEd Tanous BMCWEB_LOG_ERROR( 237062598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 237162598e31SEd Tanous ec); 2372fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2373fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2374fdd26906SClaire Weinan return; 2375fdd26906SClaire Weinan } 2376fdd26906SClaire Weinan 2377fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2378fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2379fdd26906SClaire Weinan 2380fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2381fdd26906SClaire Weinan { 2382fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2383fdd26906SClaire Weinan { 2384613dabeaSEd Tanous nlohmann::json::object_t member; 2385253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2386253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump", 2387253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2388b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2389fdd26906SClaire Weinan } 2390fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2391fdd26906SClaire Weinan { 2392613dabeaSEd Tanous nlohmann::json::object_t member; 2393253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2394253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/FaultLog", 2395253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2396b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2397fdd26906SClaire Weinan } 2398fdd26906SClaire Weinan } 2399fdd26906SClaire Weinan 2400e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2401fdd26906SClaire Weinan logServiceArrayLocal.size(); 24027a1dbc48SGeorge Liu }); 240325b54dbaSEd Tanous } 2404fdd26906SClaire Weinan } 2405fdd26906SClaire Weinan 2406fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2407fdd26906SClaire Weinan { 2408253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/") 2409fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2410fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2411dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2412e1f26343SJason M. Bills } 2413e1f26343SJason M. Bills 2414fdd26906SClaire Weinan inline void 2415fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2416fdd26906SClaire Weinan const std::string& dumpType) 2417c9bb6861Sraviteja-b { 2418fdd26906SClaire Weinan std::string dumpPath; 2419539d8c6bSEd Tanous log_service::OverWritePolicy overWritePolicy = 2420539d8c6bSEd Tanous log_service::OverWritePolicy::Invalid; 2421fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2422fdd26906SClaire Weinan 2423fdd26906SClaire Weinan if (dumpType == "BMC") 242445ca1b86SEd Tanous { 2425253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump", 2426253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2427539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::WrapsWhenFull; 2428fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2429fdd26906SClaire Weinan } 2430fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2431fdd26906SClaire Weinan { 2432253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog", 2433253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2434539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::Unknown; 2435fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2436fdd26906SClaire Weinan } 2437fdd26906SClaire Weinan else if (dumpType == "System") 2438fdd26906SClaire Weinan { 2439253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump", 2440253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2441539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::WrapsWhenFull; 2442fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2443fdd26906SClaire Weinan } 2444fdd26906SClaire Weinan else 2445fdd26906SClaire Weinan { 244662598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 244762598e31SEd Tanous dumpType); 2448fdd26906SClaire Weinan messages::internalError(asyncResp->res); 244945ca1b86SEd Tanous return; 245045ca1b86SEd Tanous } 2451fdd26906SClaire Weinan 2452fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2453fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2454c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2455fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2456fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2457539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = overWritePolicy; 24587c8c4058STejas Patil 24597c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 24602b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 24610fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 24627c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 24637c8c4058STejas Patil redfishDateTimeOffset.second; 24647c8c4058STejas Patil 2465fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2466fdd26906SClaire Weinan 2467fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2468fdd26906SClaire Weinan { 2469002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 24701476687dSEd Tanous ["target"] = 2471fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2472fdd26906SClaire Weinan } 24730d946211SClaire Weinan 24740d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 24750d946211SClaire Weinan dbus::utility::getSubTreePaths( 24760d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 24770d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 24780d946211SClaire Weinan const boost::system::error_code& ec, 24790d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 24800d946211SClaire Weinan if (ec) 24810d946211SClaire Weinan { 248262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 24830d946211SClaire Weinan // Assume that getting an error simply means there are no dump 24840d946211SClaire Weinan // LogServices. Return without adding any error response. 24850d946211SClaire Weinan return; 24860d946211SClaire Weinan } 248718f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 24880d946211SClaire Weinan for (const std::string& path : subTreePaths) 24890d946211SClaire Weinan { 24900d946211SClaire Weinan if (path == dbusDumpPath) 24910d946211SClaire Weinan { 24920d946211SClaire Weinan asyncResp->res 24930d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 24940d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 24950d946211SClaire Weinan break; 24960d946211SClaire Weinan } 24970d946211SClaire Weinan } 24980d946211SClaire Weinan }); 2499c9bb6861Sraviteja-b } 2500c9bb6861Sraviteja-b 2501fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2502fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2503253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2504253f11b8SEd Tanous const std::string& managerId) 25057e860f15SJohn Edward Broadbent { 25063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 250745ca1b86SEd Tanous { 250845ca1b86SEd Tanous return; 250945ca1b86SEd Tanous } 2510253f11b8SEd Tanous 2511253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2512253f11b8SEd Tanous { 2513253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2514253f11b8SEd Tanous return; 2515253f11b8SEd Tanous } 2516253f11b8SEd Tanous 2517fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2518fdd26906SClaire Weinan } 2519c9bb6861Sraviteja-b 252022d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 252122d268cbSEd Tanous crow::App& app, const crow::Request& req, 252222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 252322d268cbSEd Tanous const std::string& chassisId) 252422d268cbSEd Tanous { 252522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 252622d268cbSEd Tanous { 252722d268cbSEd Tanous return; 252822d268cbSEd Tanous } 2529253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 253022d268cbSEd Tanous { 253122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 253222d268cbSEd Tanous return; 253322d268cbSEd Tanous } 253422d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 253522d268cbSEd Tanous } 253622d268cbSEd Tanous 2537fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2538fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2539253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2540253f11b8SEd Tanous const std::string& managerId) 2541fdd26906SClaire Weinan { 2542fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2543fdd26906SClaire Weinan { 2544fdd26906SClaire Weinan return; 2545fdd26906SClaire Weinan } 2546253f11b8SEd Tanous 2547253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2548253f11b8SEd Tanous { 2549253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2550253f11b8SEd Tanous return; 2551253f11b8SEd Tanous } 2552fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2553fdd26906SClaire Weinan } 2554fdd26906SClaire Weinan 255522d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 255622d268cbSEd Tanous crow::App& app, const crow::Request& req, 255722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 255822d268cbSEd Tanous const std::string& chassisId) 255922d268cbSEd Tanous { 256022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 256122d268cbSEd Tanous { 256222d268cbSEd Tanous return; 256322d268cbSEd Tanous } 2564253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 256522d268cbSEd Tanous { 256622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 256722d268cbSEd Tanous return; 256822d268cbSEd Tanous } 256922d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 257022d268cbSEd Tanous } 257122d268cbSEd Tanous 2572fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2573fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2574fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2575253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2576fdd26906SClaire Weinan { 2577fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2578fdd26906SClaire Weinan { 2579fdd26906SClaire Weinan return; 2580fdd26906SClaire Weinan } 2581253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2582253f11b8SEd Tanous { 2583253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2584253f11b8SEd Tanous return; 2585253f11b8SEd Tanous } 2586fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2587fdd26906SClaire Weinan } 2588168d1b1aSCarson Labrado 258922d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 259022d268cbSEd Tanous crow::App& app, const crow::Request& req, 259122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 259222d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 259322d268cbSEd Tanous { 259422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 259522d268cbSEd Tanous { 259622d268cbSEd Tanous return; 259722d268cbSEd Tanous } 2598253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 259922d268cbSEd Tanous { 260022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 260122d268cbSEd Tanous return; 260222d268cbSEd Tanous } 260322d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 260422d268cbSEd Tanous } 2605fdd26906SClaire Weinan 2606fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2607fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2608fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2609253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2610fdd26906SClaire Weinan { 2611fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2612fdd26906SClaire Weinan { 2613fdd26906SClaire Weinan return; 2614fdd26906SClaire Weinan } 2615253f11b8SEd Tanous 2616253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2617253f11b8SEd Tanous { 2618253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2619253f11b8SEd Tanous return; 2620253f11b8SEd Tanous } 2621fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2622fdd26906SClaire Weinan } 2623fdd26906SClaire Weinan 262422d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 262522d268cbSEd Tanous crow::App& app, const crow::Request& req, 262622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 262722d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 262822d268cbSEd Tanous { 262922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 263022d268cbSEd Tanous { 263122d268cbSEd Tanous return; 263222d268cbSEd Tanous } 2633253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 263422d268cbSEd Tanous { 263522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 263622d268cbSEd Tanous return; 263722d268cbSEd Tanous } 263822d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 263922d268cbSEd Tanous } 264022d268cbSEd Tanous 2641168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2642168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2643168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2644253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2645168d1b1aSCarson Labrado { 2646168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2647168d1b1aSCarson Labrado { 2648168d1b1aSCarson Labrado return; 2649168d1b1aSCarson Labrado } 2650253f11b8SEd Tanous 2651253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2652253f11b8SEd Tanous { 2653253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2654253f11b8SEd Tanous return; 2655253f11b8SEd Tanous } 2656168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2657168d1b1aSCarson Labrado } 2658168d1b1aSCarson Labrado 2659168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2660168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2661168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2662168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2663168d1b1aSCarson Labrado { 2664168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2665168d1b1aSCarson Labrado { 2666168d1b1aSCarson Labrado return; 2667168d1b1aSCarson Labrado } 2668168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2669168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2670168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2671168d1b1aSCarson Labrado { 2672168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2673168d1b1aSCarson Labrado return; 2674168d1b1aSCarson Labrado } 2675168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2676168d1b1aSCarson Labrado } 2677168d1b1aSCarson Labrado 2678fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2679fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2680253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2681253f11b8SEd Tanous const std::string& managerId) 2682fdd26906SClaire Weinan { 2683fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2684fdd26906SClaire Weinan { 2685fdd26906SClaire Weinan return; 2686fdd26906SClaire Weinan } 2687253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2688253f11b8SEd Tanous { 2689253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2690253f11b8SEd Tanous return; 2691253f11b8SEd Tanous } 2692253f11b8SEd Tanous 2693fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2694fdd26906SClaire Weinan } 2695fdd26906SClaire Weinan 269622d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 269722d268cbSEd Tanous crow::App& app, const crow::Request& req, 269822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26997f3e84a1SEd Tanous const std::string& systemName) 270022d268cbSEd Tanous { 270122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270222d268cbSEd Tanous { 270322d268cbSEd Tanous return; 270422d268cbSEd Tanous } 27057f3e84a1SEd Tanous 270625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 270722d268cbSEd Tanous { 27087f3e84a1SEd Tanous // Option currently returns no systems. TBD 27097f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27107f3e84a1SEd Tanous systemName); 27117f3e84a1SEd Tanous return; 27127f3e84a1SEd Tanous } 2713253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 27147f3e84a1SEd Tanous { 27157f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27167f3e84a1SEd Tanous systemName); 271722d268cbSEd Tanous return; 271822d268cbSEd Tanous } 271922d268cbSEd Tanous createDump(asyncResp, req, "System"); 272022d268cbSEd Tanous } 272122d268cbSEd Tanous 2722fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2723fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2724253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2725253f11b8SEd Tanous const std::string& managerId) 2726fdd26906SClaire Weinan { 2727fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2728fdd26906SClaire Weinan { 2729fdd26906SClaire Weinan return; 2730fdd26906SClaire Weinan } 2731253f11b8SEd Tanous 2732253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2733253f11b8SEd Tanous { 2734253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2735253f11b8SEd Tanous return; 2736253f11b8SEd Tanous } 2737fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2738fdd26906SClaire Weinan } 2739fdd26906SClaire Weinan 274022d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 274122d268cbSEd Tanous crow::App& app, const crow::Request& req, 274222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27437f3e84a1SEd Tanous const std::string& systemName) 274422d268cbSEd Tanous { 274522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 274622d268cbSEd Tanous { 274722d268cbSEd Tanous return; 274822d268cbSEd Tanous } 274925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 275022d268cbSEd Tanous { 27517f3e84a1SEd Tanous // Option currently returns no systems. TBD 27527f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27537f3e84a1SEd Tanous systemName); 27547f3e84a1SEd Tanous return; 27557f3e84a1SEd Tanous } 2756253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 27577f3e84a1SEd Tanous { 27587f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 27597f3e84a1SEd Tanous systemName); 276022d268cbSEd Tanous return; 276122d268cbSEd Tanous } 276222d268cbSEd Tanous clearDump(asyncResp, "System"); 276322d268cbSEd Tanous } 276422d268cbSEd Tanous 2765fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2766fdd26906SClaire Weinan { 2767253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/") 2768fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2769fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2770fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2771fdd26906SClaire Weinan } 2772fdd26906SClaire Weinan 2773fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2774fdd26906SClaire Weinan { 2775253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/") 2776fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2777fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2778fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2779c9bb6861Sraviteja-b } 2780c9bb6861Sraviteja-b 27817e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2782c9bb6861Sraviteja-b { 27837e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2784253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2785ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2786fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2787fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2788fdd26906SClaire Weinan 27897e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2790253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2791ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2792fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2793fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2794c9bb6861Sraviteja-b } 2795c9bb6861Sraviteja-b 2796168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 2797168d1b1aSCarson Labrado { 2798168d1b1aSCarson Labrado BMCWEB_ROUTE( 2799168d1b1aSCarson Labrado app, 2800253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/") 2801168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2802168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2803168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 2804168d1b1aSCarson Labrado } 2805168d1b1aSCarson Labrado 28067e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2807c9bb6861Sraviteja-b { 28080fda0f12SGeorge Liu BMCWEB_ROUTE( 28090fda0f12SGeorge Liu app, 2810253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2811ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28127e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2813fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2814fdd26906SClaire Weinan std::ref(app), "BMC")); 2815a43be80fSAsmitha Karunanithi } 2816a43be80fSAsmitha Karunanithi 28177e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 281880319af1SAsmitha Karunanithi { 28190fda0f12SGeorge Liu BMCWEB_ROUTE( 28200fda0f12SGeorge Liu app, 2821253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2822ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2823fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2824fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 282545ca1b86SEd Tanous } 2826fdd26906SClaire Weinan 2827168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 2828168d1b1aSCarson Labrado { 2829168d1b1aSCarson Labrado BMCWEB_ROUTE( 2830168d1b1aSCarson Labrado app, 28319e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 2832168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2833168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2834168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 2835168d1b1aSCarson Labrado } 2836168d1b1aSCarson Labrado 2837fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2838fdd26906SClaire Weinan { 2839253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/") 2840fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2841fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2842fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2843fdd26906SClaire Weinan } 2844fdd26906SClaire Weinan 2845fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2846fdd26906SClaire Weinan { 2847253f11b8SEd Tanous BMCWEB_ROUTE(app, 2848253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/") 2849fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2850fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2851fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2852fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2853fdd26906SClaire Weinan } 2854fdd26906SClaire Weinan 2855fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2856fdd26906SClaire Weinan { 2857253f11b8SEd Tanous BMCWEB_ROUTE( 2858253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2859fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2860fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2861fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2862fdd26906SClaire Weinan 2863253f11b8SEd Tanous BMCWEB_ROUTE( 2864253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2865fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2866fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2867fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2868fdd26906SClaire Weinan } 2869fdd26906SClaire Weinan 2870fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2871fdd26906SClaire Weinan { 2872fdd26906SClaire Weinan BMCWEB_ROUTE( 2873fdd26906SClaire Weinan app, 2874253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/") 2875fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2876fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2877fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 28785cb1dd27SAsmitha Karunanithi } 28795cb1dd27SAsmitha Karunanithi 28807e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 28815cb1dd27SAsmitha Karunanithi { 288222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2883ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 28846ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 288522d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 28865cb1dd27SAsmitha Karunanithi } 28875cb1dd27SAsmitha Karunanithi 28887e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 28897e860f15SJohn Edward Broadbent { 289022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2891ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 289222d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 289322d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 289422d268cbSEd Tanous std::ref(app))); 28955cb1dd27SAsmitha Karunanithi } 28965cb1dd27SAsmitha Karunanithi 28977e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 28985cb1dd27SAsmitha Karunanithi { 28997e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 290022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2901ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29026ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 290322d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29048d1b46d7Szhanghch05 29057e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 290622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2907ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29086ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 290922d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29105cb1dd27SAsmitha Karunanithi } 2911c9bb6861Sraviteja-b 29127e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2913c9bb6861Sraviteja-b { 29140fda0f12SGeorge Liu BMCWEB_ROUTE( 29150fda0f12SGeorge Liu app, 291622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2917ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 291822d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 291922d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 292022d268cbSEd Tanous std::ref(app))); 2921a43be80fSAsmitha Karunanithi } 2922a43be80fSAsmitha Karunanithi 29237e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2924a43be80fSAsmitha Karunanithi { 29250fda0f12SGeorge Liu BMCWEB_ROUTE( 29260fda0f12SGeorge Liu app, 292722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2928ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29296ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 293022d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2931013487e5Sraviteja-b } 2932013487e5Sraviteja-b 29337e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29341da66f75SEd Tanous { 29353946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29363946028dSAppaRao Puli // method for security reasons. 29371da66f75SEd Tanous /** 29381da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29391da66f75SEd Tanous */ 294022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2941ed398213SEd Tanous // This is incorrect, should be: 2942ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2943432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2944002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2945002d39b4SEd Tanous [&app](const crow::Request& req, 294622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 294722d268cbSEd Tanous const std::string& systemName) { 29483ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 294945ca1b86SEd Tanous { 295045ca1b86SEd Tanous return; 295145ca1b86SEd Tanous } 295225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 29537f3e84a1SEd Tanous { 29547f3e84a1SEd Tanous // Option currently returns no systems. TBD 29557f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29567f3e84a1SEd Tanous systemName); 29577f3e84a1SEd Tanous return; 29587f3e84a1SEd Tanous } 2959253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 296022d268cbSEd Tanous { 296122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 296222d268cbSEd Tanous systemName); 296322d268cbSEd Tanous return; 296422d268cbSEd Tanous } 296522d268cbSEd Tanous 29667e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29677e860f15SJohn Edward Broadbent // SubRoute 29680f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2969253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 2970253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2971e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 29728e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 29734f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 29744f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 297515b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 2976539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 2977539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 2978e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 29797c8c4058STejas Patil 29807c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 29812b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 29827c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 29837c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 29847c8c4058STejas Patil redfishDateTimeOffset.second; 29857c8c4058STejas Patil 29861476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 2987253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 2988253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2989253f11b8SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 2990253f11b8SEd Tanous ["target"] = std::format( 2991253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog", 2992253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2993002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 2994253f11b8SEd Tanous ["target"] = std::format( 2995253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData", 2996253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 29977e860f15SJohn Edward Broadbent }); 29981da66f75SEd Tanous } 29991da66f75SEd Tanous 30007e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30015b61b5e8SJason M. Bills { 30020fda0f12SGeorge Liu BMCWEB_ROUTE( 30030fda0f12SGeorge Liu app, 300422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3005ed398213SEd Tanous // This is incorrect, should be: 3006ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3007432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30087e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 300945ca1b86SEd Tanous [&app](const crow::Request& req, 301022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 301122d268cbSEd Tanous const std::string& systemName) { 30123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 301345ca1b86SEd Tanous { 301445ca1b86SEd Tanous return; 301545ca1b86SEd Tanous } 301625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 30177f3e84a1SEd Tanous { 30187f3e84a1SEd Tanous // Option currently returns no systems. TBD 30197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30207f3e84a1SEd Tanous systemName); 30217f3e84a1SEd Tanous return; 30227f3e84a1SEd Tanous } 3023253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 302422d268cbSEd Tanous { 302522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 302622d268cbSEd Tanous systemName); 302722d268cbSEd Tanous return; 302822d268cbSEd Tanous } 30295b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30305e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3031cb13a392SEd Tanous const std::string&) { 30325b61b5e8SJason M. Bills if (ec) 30335b61b5e8SJason M. Bills { 30345b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30355b61b5e8SJason M. Bills return; 30365b61b5e8SJason M. Bills } 30375b61b5e8SJason M. Bills messages::success(asyncResp->res); 30385b61b5e8SJason M. Bills }, 3039002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30407e860f15SJohn Edward Broadbent }); 30415b61b5e8SJason M. Bills } 30425b61b5e8SJason M. Bills 30438d1b46d7Szhanghch05 static void 30448d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30458d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3046e855dd28SJason M. Bills { 3047043a0536SJohnathan Mantey auto getStoredLogCallback = 3048b9d36b47SEd Tanous [asyncResp, logID, 30495e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3050b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3051e855dd28SJason M. Bills if (ec) 3052e855dd28SJason M. Bills { 305362598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 30541ddcf01aSJason M. Bills if (ec.value() == 30551ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30561ddcf01aSJason M. Bills { 3057002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30581ddcf01aSJason M. Bills } 30591ddcf01aSJason M. Bills else 30601ddcf01aSJason M. Bills { 3061e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30621ddcf01aSJason M. Bills } 3063e855dd28SJason M. Bills return; 3064e855dd28SJason M. Bills } 3065043a0536SJohnathan Mantey 3066043a0536SJohnathan Mantey std::string timestamp{}; 3067043a0536SJohnathan Mantey std::string filename{}; 3068043a0536SJohnathan Mantey std::string logfile{}; 30692c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3070043a0536SJohnathan Mantey 3071043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3072e855dd28SJason M. Bills { 30739db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3074e855dd28SJason M. Bills return; 3075e855dd28SJason M. Bills } 3076e855dd28SJason M. Bills 3077043a0536SJohnathan Mantey std::string crashdumpURI = 3078253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/", 3079253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3080043a0536SJohnathan Mantey logID + "/" + filename; 308184afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30829c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3083ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3084253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}", 3085253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logID); 308684afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 308784afc48bSJason M. Bills logEntry["Id"] = logID; 3088539d8c6bSEd Tanous logEntry["EntryType"] = log_entry::LogEntryType::Oem; 308984afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 309084afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 309184afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 309284afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 30932b20ef6eSJason M. Bills 30942b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 30952b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 30962b20ef6eSJason M. Bills // directly 30972b20ef6eSJason M. Bills if (logEntryJson.is_array()) 30982b20ef6eSJason M. Bills { 30992b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 31002b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 31012b20ef6eSJason M. Bills logEntryJson.size(); 31022b20ef6eSJason M. Bills } 31032b20ef6eSJason M. Bills else 31042b20ef6eSJason M. Bills { 3105d405bb51SJason M. Bills logEntryJson.update(logEntry); 31062b20ef6eSJason M. Bills } 3107e855dd28SJason M. Bills }; 3108d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3109d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3110d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3111d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3112e855dd28SJason M. Bills } 3113e855dd28SJason M. Bills 31147e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31151da66f75SEd Tanous { 31163946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31173946028dSAppaRao Puli // method for security reasons. 31181da66f75SEd Tanous /** 31191da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31201da66f75SEd Tanous */ 31217e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 312222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3123ed398213SEd Tanous // This is incorrect, should be. 3124ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3125432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3126002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3127002d39b4SEd Tanous [&app](const crow::Request& req, 312822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 312922d268cbSEd Tanous const std::string& systemName) { 31303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 313145ca1b86SEd Tanous { 313245ca1b86SEd Tanous return; 313345ca1b86SEd Tanous } 313425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 31357f3e84a1SEd Tanous { 31367f3e84a1SEd Tanous // Option currently returns no systems. TBD 31377f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31387f3e84a1SEd Tanous systemName); 31397f3e84a1SEd Tanous return; 31407f3e84a1SEd Tanous } 3141253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 314222d268cbSEd Tanous { 314322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 314422d268cbSEd Tanous systemName); 314522d268cbSEd Tanous return; 314622d268cbSEd Tanous } 314722d268cbSEd Tanous 31487a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 31497a1dbc48SGeorge Liu crashdumpInterface}; 31507a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 31517a1dbc48SGeorge Liu "/", 0, interfaces, 31527a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 31532b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31541da66f75SEd Tanous if (ec) 31551da66f75SEd Tanous { 31561da66f75SEd Tanous if (ec.value() != 31571da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31581da66f75SEd Tanous { 315962598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 316062598e31SEd Tanous ec.message()); 3161f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31621da66f75SEd Tanous return; 31631da66f75SEd Tanous } 31641da66f75SEd Tanous } 3165e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31661da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 3167253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 3168253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 3169253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3170002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3171e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3172424c4176SJason M. Bills "Collection of Crashdump Entries"; 3173002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3174a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31752b20ef6eSJason M. Bills 31762b20ef6eSJason M. Bills for (const std::string& path : resp) 31771da66f75SEd Tanous { 31782b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3179e855dd28SJason M. Bills // Get the log ID 31802b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31812b20ef6eSJason M. Bills if (logID.empty()) 31821da66f75SEd Tanous { 3183e855dd28SJason M. Bills continue; 31841da66f75SEd Tanous } 3185e855dd28SJason M. Bills // Add the log entry to the array 31862b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31872b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31881da66f75SEd Tanous } 31897a1dbc48SGeorge Liu }); 31907e860f15SJohn Edward Broadbent }); 31911da66f75SEd Tanous } 31921da66f75SEd Tanous 31937e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31941da66f75SEd Tanous { 31953946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31963946028dSAppaRao Puli // method for security reasons. 31971da66f75SEd Tanous 31987e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 319922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3200ed398213SEd Tanous // this is incorrect, should be 3201ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3202432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 320445ca1b86SEd Tanous [&app](const crow::Request& req, 32057e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 320622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 32073ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 320845ca1b86SEd Tanous { 320945ca1b86SEd Tanous return; 321045ca1b86SEd 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 } 32247e860f15SJohn Edward Broadbent const std::string& logID = param; 3225e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32267e860f15SJohn Edward Broadbent }); 3227e855dd28SJason M. Bills } 3228e855dd28SJason M. Bills 32297e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3230e855dd28SJason M. Bills { 32313946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32323946028dSAppaRao Puli // method for security reasons. 32337e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32347e860f15SJohn Edward Broadbent app, 323522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3236ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32377e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3238a4ce114aSNan Zhou [](const crow::Request& req, 32397e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324022d268cbSEd Tanous const std::string& systemName, const std::string& logID, 324122d268cbSEd Tanous const std::string& fileName) { 32422a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32432a9beeedSShounak Mitra // Redfish resource. 324422d268cbSEd Tanous 324525b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 32467f3e84a1SEd Tanous { 32477f3e84a1SEd Tanous // Option currently returns no systems. TBD 32487f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32497f3e84a1SEd Tanous systemName); 32507f3e84a1SEd Tanous return; 32517f3e84a1SEd Tanous } 3252253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 325322d268cbSEd Tanous { 325422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 325522d268cbSEd Tanous systemName); 325622d268cbSEd Tanous return; 325722d268cbSEd Tanous } 325822d268cbSEd Tanous 3259043a0536SJohnathan Mantey auto getStoredLogCallback = 326039662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 32615e7e2dc5SEd Tanous const boost::system::error_code& ec, 3262002d39b4SEd Tanous const std::vector< 3263002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32647e860f15SJohn Edward Broadbent resp) { 32651da66f75SEd Tanous if (ec) 32661da66f75SEd Tanous { 326762598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3268f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32691da66f75SEd Tanous return; 32701da66f75SEd Tanous } 3271e855dd28SJason M. Bills 3272043a0536SJohnathan Mantey std::string dbusFilename{}; 3273043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3274043a0536SJohnathan Mantey std::string dbusFilepath{}; 3275043a0536SJohnathan Mantey 3276002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3277002d39b4SEd Tanous dbusFilepath); 3278043a0536SJohnathan Mantey 3279043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3280043a0536SJohnathan Mantey dbusFilepath.empty()) 32811da66f75SEd Tanous { 32829db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32831da66f75SEd Tanous return; 32841da66f75SEd Tanous } 3285e855dd28SJason M. Bills 3286043a0536SJohnathan Mantey // Verify the file name parameter is correct 3287043a0536SJohnathan Mantey if (fileName != dbusFilename) 3288043a0536SJohnathan Mantey { 32899db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3290043a0536SJohnathan Mantey return; 3291043a0536SJohnathan Mantey } 3292043a0536SJohnathan Mantey 329327b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3294043a0536SJohnathan Mantey { 32959db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3296043a0536SJohnathan Mantey return; 3297043a0536SJohnathan Mantey } 3298043a0536SJohnathan Mantey 32997e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 33007e860f15SJohn Edward Broadbent // from a browser 3301d9f6c621SEd Tanous asyncResp->res.addHeader( 3302d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 33031da66f75SEd Tanous }; 3304d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3305d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3306d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3307d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 33087e860f15SJohn Edward Broadbent }); 33091da66f75SEd Tanous } 33101da66f75SEd Tanous 3311c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3312c5a4c82aSJason M. Bills { 3313c5a4c82aSJason M. Bills onDemand, 3314c5a4c82aSJason M. Bills telemetry, 3315c5a4c82aSJason M. Bills invalid, 3316c5a4c82aSJason M. Bills }; 3317c5a4c82aSJason M. Bills 331826ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3319c5a4c82aSJason M. Bills { 3320c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3321c5a4c82aSJason M. Bills { 3322c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3323c5a4c82aSJason M. Bills } 3324c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3325c5a4c82aSJason M. Bills { 3326c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3327c5a4c82aSJason M. Bills } 3328c5a4c82aSJason M. Bills 3329c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3330c5a4c82aSJason M. Bills } 3331c5a4c82aSJason M. Bills 33327e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33331da66f75SEd Tanous { 33343946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33353946028dSAppaRao Puli // method for security reasons. 33360fda0f12SGeorge Liu BMCWEB_ROUTE( 33370fda0f12SGeorge Liu app, 333822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3339ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3340ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3341432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3342002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3343002d39b4SEd Tanous [&app](const crow::Request& req, 334422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 334522d268cbSEd Tanous const std::string& systemName) { 33463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 334745ca1b86SEd Tanous { 334845ca1b86SEd Tanous return; 334945ca1b86SEd Tanous } 335022d268cbSEd Tanous 335125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 33527f3e84a1SEd Tanous { 33537f3e84a1SEd Tanous // Option currently returns no systems. TBD 33547f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33557f3e84a1SEd Tanous systemName); 33567f3e84a1SEd Tanous return; 33577f3e84a1SEd Tanous } 3358253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 335922d268cbSEd Tanous { 336022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 336122d268cbSEd Tanous systemName); 336222d268cbSEd Tanous return; 336322d268cbSEd Tanous } 336422d268cbSEd Tanous 33658e6c099aSJason M. Bills std::string diagnosticDataType; 33668e6c099aSJason M. Bills std::string oemDiagnosticDataType; 336715ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3368002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3369002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33708e6c099aSJason M. Bills { 33718e6c099aSJason M. Bills return; 33728e6c099aSJason M. Bills } 33738e6c099aSJason M. Bills 33748e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33758e6c099aSJason M. Bills { 337662598e31SEd Tanous BMCWEB_LOG_ERROR( 337762598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 33788e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33798e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33808e6c099aSJason M. Bills "CollectDiagnosticData"); 33818e6c099aSJason M. Bills return; 33828e6c099aSJason M. Bills } 33838e6c099aSJason M. Bills 3384c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3385c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3386c5a4c82aSJason M. Bills 3387c5a4c82aSJason M. Bills std::string iface; 3388c5a4c82aSJason M. Bills std::string method; 3389c5a4c82aSJason M. Bills std::string taskMatchStr; 3390c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3391c5a4c82aSJason M. Bills { 3392c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3393c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3394c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3395c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3396c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3397c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3398c5a4c82aSJason M. Bills } 3399c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3400c5a4c82aSJason M. Bills { 3401c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3402c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3403c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3404c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3405c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3406c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3407c5a4c82aSJason M. Bills } 3408c5a4c82aSJason M. Bills else 3409c5a4c82aSJason M. Bills { 341062598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 341162598e31SEd Tanous oemDiagnosticDataType); 3412c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3413002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3414002d39b4SEd Tanous "CollectDiagnosticData"); 3415c5a4c82aSJason M. Bills return; 3416c5a4c82aSJason M. Bills } 3417c5a4c82aSJason M. Bills 3418c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3419c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 34205e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 342198be3e39SEd Tanous const std::string&) mutable { 34221da66f75SEd Tanous if (ec) 34231da66f75SEd Tanous { 3424002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 34251da66f75SEd Tanous { 3426f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 34271da66f75SEd Tanous } 34284363d3b2SJason M. Bills else if (ec.value() == 34294363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 34304363d3b2SJason M. Bills { 3431002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3432002d39b4SEd Tanous "60"); 34334363d3b2SJason M. Bills } 34341da66f75SEd Tanous else 34351da66f75SEd Tanous { 3436f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34371da66f75SEd Tanous } 34381da66f75SEd Tanous return; 34391da66f75SEd Tanous } 3440002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 34418b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3442002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 34438b24275dSEd Tanous if (!ec2) 344466afe4faSJames Feist { 3445002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3446e5d5006bSJames Feist std::to_string(taskData->index))); 3447831d6b09SJames Feist taskData->state = "Completed"; 344866afe4faSJames Feist } 344932898ceaSJames Feist return task::completed; 345066afe4faSJames Feist }, 3451c5a4c82aSJason M. Bills taskMatchStr); 3452c5a4c82aSJason M. Bills 345346229577SJames Feist task->startTimer(std::chrono::minutes(5)); 345446229577SJames Feist task->populateResp(asyncResp->res); 345598be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34561da66f75SEd Tanous }; 34578e6c099aSJason M. Bills 34581da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3459002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3460002d39b4SEd Tanous iface, method); 34617e860f15SJohn Edward Broadbent }); 34626eda7685SKenny L. Ku } 34636eda7685SKenny L. Ku 3464*599b9af3SAlexander Hansen inline void dBusLogServiceActionsClear( 3465*599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3466*599b9af3SAlexander Hansen { 3467*599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Do delete all entries."); 3468*599b9af3SAlexander Hansen 3469*599b9af3SAlexander Hansen // Process response from Logging service. 3470*599b9af3SAlexander Hansen auto respHandler = [asyncResp](const boost::system::error_code& ec) { 3471*599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3472*599b9af3SAlexander Hansen if (ec) 3473*599b9af3SAlexander Hansen { 3474*599b9af3SAlexander Hansen // TODO Handle for specific error code 3475*599b9af3SAlexander Hansen BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3476*599b9af3SAlexander Hansen asyncResp->res.result( 3477*599b9af3SAlexander Hansen boost::beast::http::status::internal_server_error); 3478*599b9af3SAlexander Hansen return; 3479*599b9af3SAlexander Hansen } 3480*599b9af3SAlexander Hansen 3481*599b9af3SAlexander Hansen asyncResp->res.result(boost::beast::http::status::no_content); 3482*599b9af3SAlexander Hansen }; 3483*599b9af3SAlexander Hansen 3484*599b9af3SAlexander Hansen // Make call to Logging service to request Clear Log 3485*599b9af3SAlexander Hansen crow::connections::systemBus->async_method_call( 3486*599b9af3SAlexander Hansen respHandler, "xyz.openbmc_project.Logging", 3487*599b9af3SAlexander Hansen "/xyz/openbmc_project/logging", 3488*599b9af3SAlexander Hansen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 3489*599b9af3SAlexander Hansen } 3490*599b9af3SAlexander Hansen 3491cb92c03bSAndrew Geissler /** 3492cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3493cb92c03bSAndrew Geissler */ 34947e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3495cb92c03bSAndrew Geissler { 3496cb92c03bSAndrew Geissler /** 3497cb92c03bSAndrew Geissler * Function handles POST method request. 3498cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3499cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3500cb92c03bSAndrew Geissler */ 35017e860f15SJohn Edward Broadbent 35020fda0f12SGeorge Liu BMCWEB_ROUTE( 35030fda0f12SGeorge Liu app, 350422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3505ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 35067e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 350745ca1b86SEd Tanous [&app](const crow::Request& req, 350822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350922d268cbSEd Tanous const std::string& systemName) { 35103ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 351145ca1b86SEd Tanous { 351245ca1b86SEd Tanous return; 351345ca1b86SEd Tanous } 351425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35157f3e84a1SEd Tanous { 35167f3e84a1SEd Tanous // Option currently returns no systems. TBD 35177f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35187f3e84a1SEd Tanous systemName); 35197f3e84a1SEd Tanous return; 35207f3e84a1SEd Tanous } 3521253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 352222d268cbSEd Tanous { 352322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 352422d268cbSEd Tanous systemName); 352522d268cbSEd Tanous return; 352622d268cbSEd Tanous } 3527*599b9af3SAlexander Hansen dBusLogServiceActionsClear(asyncResp); 35287e860f15SJohn Edward Broadbent }); 3529cb92c03bSAndrew Geissler } 3530a3316fc6SZhikuiRen 3531a3316fc6SZhikuiRen /**************************************************** 3532a3316fc6SZhikuiRen * Redfish PostCode interfaces 3533a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3534a3316fc6SZhikuiRen ******************************************************/ 35357e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3536a3316fc6SZhikuiRen { 353722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3538ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3539002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3540002d39b4SEd Tanous [&app](const crow::Request& req, 354122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 354222d268cbSEd Tanous const std::string& systemName) { 35433ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 354445ca1b86SEd Tanous { 354545ca1b86SEd Tanous return; 354645ca1b86SEd Tanous } 354725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35487f3e84a1SEd Tanous { 35497f3e84a1SEd Tanous // Option currently returns no systems. TBD 35507f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35517f3e84a1SEd Tanous systemName); 35527f3e84a1SEd Tanous return; 35537f3e84a1SEd Tanous } 3554253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 355522d268cbSEd Tanous { 355622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 355722d268cbSEd Tanous systemName); 355822d268cbSEd Tanous return; 355922d268cbSEd Tanous } 35601476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3561253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 3562253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35631476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3564b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 35651476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35661476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3567ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 3568539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 3569539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 35701476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3571253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3572253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35737c8c4058STejas Patil 35747c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35752b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35760fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35777c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35787c8c4058STejas Patil redfishDateTimeOffset.second; 35797c8c4058STejas Patil 358020fa6a2cSEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 358120fa6a2cSEd Tanous ["target"] = std::format( 3582253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 358320fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35847e860f15SJohn Edward Broadbent }); 3585a3316fc6SZhikuiRen } 3586a3316fc6SZhikuiRen 35877e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3588a3316fc6SZhikuiRen { 35890fda0f12SGeorge Liu BMCWEB_ROUTE( 35900fda0f12SGeorge Liu app, 359122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3592ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3593ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3594432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35957e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 359645ca1b86SEd Tanous [&app](const crow::Request& req, 359722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 359822d268cbSEd Tanous const std::string& systemName) { 35993ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 360045ca1b86SEd Tanous { 360145ca1b86SEd Tanous return; 360245ca1b86SEd Tanous } 360325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 36047f3e84a1SEd Tanous { 36057f3e84a1SEd Tanous // Option currently returns no systems. TBD 36067f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36077f3e84a1SEd Tanous systemName); 36087f3e84a1SEd Tanous return; 36097f3e84a1SEd Tanous } 3610253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 361122d268cbSEd Tanous { 361222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 361322d268cbSEd Tanous systemName); 361422d268cbSEd Tanous return; 361522d268cbSEd Tanous } 361662598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3617a3316fc6SZhikuiRen 3618a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3619a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 36205e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3621a3316fc6SZhikuiRen if (ec) 3622a3316fc6SZhikuiRen { 3623a3316fc6SZhikuiRen // TODO Handle for specific error code 362462598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 362562598e31SEd Tanous ec); 3626002d39b4SEd Tanous asyncResp->res.result( 3627002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3628a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3629a3316fc6SZhikuiRen return; 3630a3316fc6SZhikuiRen } 363118fc70c0STony Lee messages::success(asyncResp->res); 3632a3316fc6SZhikuiRen }, 363315124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 363415124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3635a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 36367e860f15SJohn Edward Broadbent }); 3637a3316fc6SZhikuiRen } 3638a3316fc6SZhikuiRen 36396f284d24SJiaqing Zhao /** 36406f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 36416f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 36426f284d24SJiaqing Zhao * 36436f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 36446f284d24SJiaqing Zhao * @param[out] currentValue Current value 36456f284d24SJiaqing Zhao * @param[out] index Index value 36466f284d24SJiaqing Zhao * 36476f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 36486f284d24SJiaqing Zhao */ 36496f056f24SEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 3650df254f2cSEd Tanous uint16_t& index) 36516f284d24SJiaqing Zhao { 36526f284d24SJiaqing Zhao std::vector<std::string> split; 365350ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 36546f056f24SEd Tanous if (split.size() != 2) 36556f056f24SEd Tanous { 36566f056f24SEd Tanous return false; 36576f056f24SEd Tanous } 36586f056f24SEd Tanous std::string_view postCodeNumber = split[0]; 36596f056f24SEd Tanous if (postCodeNumber.size() < 2) 36606f056f24SEd Tanous { 36616f056f24SEd Tanous return false; 36626f056f24SEd Tanous } 36636f056f24SEd Tanous if (postCodeNumber[0] != 'B') 36646f056f24SEd Tanous { 36656f056f24SEd Tanous return false; 36666f056f24SEd Tanous } 36676f056f24SEd Tanous postCodeNumber.remove_prefix(1); 36686f056f24SEd Tanous auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(), 36696f056f24SEd Tanous postCodeNumber.end(), index); 36706f056f24SEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 36716f284d24SJiaqing Zhao { 36726f284d24SJiaqing Zhao return false; 36736f284d24SJiaqing Zhao } 36746f284d24SJiaqing Zhao 36756f056f24SEd Tanous std::string_view postCodeIndex = split[1]; 36766f284d24SJiaqing Zhao 36776f056f24SEd Tanous auto [ptrValue, ecValue] = std::from_chars( 36786f056f24SEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 36796f284d24SJiaqing Zhao 36806f056f24SEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 36816f284d24SJiaqing Zhao } 36826f284d24SJiaqing Zhao 36836f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3684ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36856c9a279eSManojkiran Eda const boost::container::flat_map< 36866c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3687a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3688a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3689a3316fc6SZhikuiRen { 3690a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3691fffb8c1fSEd Tanous const registries::Message* message = 3692fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3693dc8cfa66SEd Tanous if (message == nullptr) 3694dc8cfa66SEd Tanous { 3695dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 3696dc8cfa66SEd Tanous return false; 3697dc8cfa66SEd Tanous } 3698a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3699a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 37006c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37016c9a279eSManojkiran Eda code : postcode) 3702a3316fc6SZhikuiRen { 3703a3316fc6SZhikuiRen currentCodeIndex++; 3704a3316fc6SZhikuiRen std::string postcodeEntryID = 3705a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3706a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3707a3316fc6SZhikuiRen 3708a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3709a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3710a3316fc6SZhikuiRen 3711a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3712a3316fc6SZhikuiRen { // already incremented 3713a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3714a3316fc6SZhikuiRen } 3715a3316fc6SZhikuiRen else 3716a3316fc6SZhikuiRen { 3717a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3718a3316fc6SZhikuiRen } 3719a3316fc6SZhikuiRen 3720a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3721a3316fc6SZhikuiRen // not fall between top and skip 3722a3316fc6SZhikuiRen if ((codeIndex == 0) && 3723a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3724a3316fc6SZhikuiRen { 3725a3316fc6SZhikuiRen continue; 3726a3316fc6SZhikuiRen } 3727a3316fc6SZhikuiRen 37284e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3729a3316fc6SZhikuiRen // currentIndex 3730a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3731a3316fc6SZhikuiRen { 3732a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3733a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3734a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3735a3316fc6SZhikuiRen continue; 3736a3316fc6SZhikuiRen } 3737a3316fc6SZhikuiRen 3738a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3739a3316fc6SZhikuiRen // index 3740a3316fc6SZhikuiRen 3741a3316fc6SZhikuiRen // Get the Created time from the timestamp 3742a3316fc6SZhikuiRen std::string entryTimeStr; 37432a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3744a3316fc6SZhikuiRen 3745a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3746a3316fc6SZhikuiRen std::ostringstream hexCode; 3747a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 37486c9a279eSManojkiran Eda << std::get<0>(code.second); 3749a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3750a3316fc6SZhikuiRen // Set Fixed -Point Notation 3751a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3752a3316fc6SZhikuiRen // Set precision to 4 digits 3753a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3754a3316fc6SZhikuiRen // Add double to stream 3755a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3756a3316fc6SZhikuiRen 37571e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 37581e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 37591e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3760a3316fc6SZhikuiRen 37611e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 37621e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 37631e6deaf6SEd Tanous 37641e6deaf6SEd Tanous std::string msg = 37651e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 37661e6deaf6SEd Tanous if (msg.empty()) 3767a3316fc6SZhikuiRen { 37681e6deaf6SEd Tanous messages::internalError(asyncResp->res); 37691e6deaf6SEd Tanous return false; 3770a3316fc6SZhikuiRen } 3771a3316fc6SZhikuiRen 3772d4342a92STim Lee // Get Severity template from message registry 3773d4342a92STim Lee std::string severity; 3774d4342a92STim Lee if (message != nullptr) 3775d4342a92STim Lee { 37765f2b84eeSEd Tanous severity = message->messageSeverity; 3777d4342a92STim Lee } 3778d4342a92STim Lee 37796f284d24SJiaqing Zhao // Format entry 37806f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37819c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3782ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 3783253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 3784253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 378584afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 378684afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 378784afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 378884afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 37891e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 379084afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 379184afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 379284afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3793647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3794647b3cdcSGeorge Liu { 3795647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3796253f11b8SEd Tanous std::format( 3797253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 3798253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3799647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3800647b3cdcSGeorge Liu } 38016f284d24SJiaqing Zhao 38026f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 38036f284d24SJiaqing Zhao // that entry in this case 38046f284d24SJiaqing Zhao if (codeIndex != 0) 38056f284d24SJiaqing Zhao { 3806ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 38076f284d24SJiaqing Zhao return true; 3808a3316fc6SZhikuiRen } 38096f284d24SJiaqing Zhao 3810ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3811b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 38126f284d24SJiaqing Zhao } 38136f284d24SJiaqing Zhao 38146f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 38156f284d24SJiaqing Zhao return false; 3816a3316fc6SZhikuiRen } 3817a3316fc6SZhikuiRen 3818ac106bf6SEd Tanous static void 3819ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 38206f284d24SJiaqing Zhao const std::string& entryId) 3821a3316fc6SZhikuiRen { 38226f284d24SJiaqing Zhao uint16_t bootIndex = 0; 38236f284d24SJiaqing Zhao uint64_t codeIndex = 0; 38246f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 38256f284d24SJiaqing Zhao { 38266f284d24SJiaqing Zhao // Requested ID was not found 3827ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38286f284d24SJiaqing Zhao return; 38296f284d24SJiaqing Zhao } 38306f284d24SJiaqing Zhao 38316f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 38326f284d24SJiaqing Zhao { 38336f284d24SJiaqing Zhao // 0 is an invalid index 3834ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38356f284d24SJiaqing Zhao return; 38366f284d24SJiaqing Zhao } 38376f284d24SJiaqing Zhao 3838a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3839ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 38405e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 38416c9a279eSManojkiran Eda const boost::container::flat_map< 38426c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38436c9a279eSManojkiran Eda postcode) { 3844a3316fc6SZhikuiRen if (ec) 3845a3316fc6SZhikuiRen { 384662598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3847ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3848a3316fc6SZhikuiRen return; 3849a3316fc6SZhikuiRen } 3850a3316fc6SZhikuiRen 3851a3316fc6SZhikuiRen if (postcode.empty()) 3852a3316fc6SZhikuiRen { 3853ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3854a3316fc6SZhikuiRen return; 3855a3316fc6SZhikuiRen } 3856a3316fc6SZhikuiRen 3857ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 38586f284d24SJiaqing Zhao { 3859ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38606f284d24SJiaqing Zhao return; 38616f284d24SJiaqing Zhao } 3862a3316fc6SZhikuiRen }, 386315124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 386415124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3865a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3866a3316fc6SZhikuiRen bootIndex); 3867a3316fc6SZhikuiRen } 3868a3316fc6SZhikuiRen 3869ac106bf6SEd Tanous static void 3870ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3871ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3872ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3873a3316fc6SZhikuiRen { 3874a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3875ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 38765e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 38776c9a279eSManojkiran Eda const boost::container::flat_map< 38786c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38796c9a279eSManojkiran Eda postcode) { 3880a3316fc6SZhikuiRen if (ec) 3881a3316fc6SZhikuiRen { 388262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3883ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3884a3316fc6SZhikuiRen return; 3885a3316fc6SZhikuiRen } 3886a3316fc6SZhikuiRen 3887a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3888a3316fc6SZhikuiRen if (!postcode.empty()) 3889a3316fc6SZhikuiRen { 3890a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38913648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3892a3316fc6SZhikuiRen { 389389492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 389489492a15SPatrick Williams entryCount) - 38953648c8beSEd Tanous entryCount; 3896a3316fc6SZhikuiRen uint64_t thisBootTop = 38973648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38983648c8beSEd Tanous entryCount; 3899a3316fc6SZhikuiRen 3900ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3901ac106bf6SEd Tanous thisBootSkip, thisBootTop); 3902a3316fc6SZhikuiRen } 3903ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3904a3316fc6SZhikuiRen } 3905a3316fc6SZhikuiRen 3906a3316fc6SZhikuiRen // continue to previous bootIndex 3907a3316fc6SZhikuiRen if (bootIndex < bootCount) 3908a3316fc6SZhikuiRen { 3909ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 3910a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3911a3316fc6SZhikuiRen } 391281584abeSJiaqing Zhao else if (skip + top < endCount) 3913a3316fc6SZhikuiRen { 3914ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 3915253f11b8SEd Tanous std::format( 3916253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 3917253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3918a3316fc6SZhikuiRen std::to_string(skip + top); 3919a3316fc6SZhikuiRen } 3920a3316fc6SZhikuiRen }, 392115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 392215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3923a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3924a3316fc6SZhikuiRen bootIndex); 3925a3316fc6SZhikuiRen } 3926a3316fc6SZhikuiRen 39278d1b46d7Szhanghch05 static void 3928ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39293648c8beSEd Tanous size_t skip, size_t top) 3930a3316fc6SZhikuiRen { 3931a3316fc6SZhikuiRen uint64_t entryCount = 0; 39321e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 39331e1e598dSJonathan Doman *crow::connections::systemBus, 39341e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 39351e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 39361e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 3937ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 39381e1e598dSJonathan Doman const uint16_t bootCount) { 3939a3316fc6SZhikuiRen if (ec) 3940a3316fc6SZhikuiRen { 394162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 3942ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3943a3316fc6SZhikuiRen return; 3944a3316fc6SZhikuiRen } 3945ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 39461e1e598dSJonathan Doman }); 3947a3316fc6SZhikuiRen } 3948a3316fc6SZhikuiRen 39497e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3950a3316fc6SZhikuiRen { 39517e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 395222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3953ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 39547e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 395545ca1b86SEd Tanous [&app](const crow::Request& req, 395622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 395722d268cbSEd Tanous const std::string& systemName) { 3958c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3959c937d2bfSEd Tanous .canDelegateTop = true, 3960c937d2bfSEd Tanous .canDelegateSkip = true, 3961c937d2bfSEd Tanous }; 3962c937d2bfSEd Tanous query_param::Query delegatedQuery; 3963c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39643ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 396545ca1b86SEd Tanous { 396645ca1b86SEd Tanous return; 396745ca1b86SEd Tanous } 396825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39697f3e84a1SEd Tanous { 39707f3e84a1SEd Tanous // Option currently returns no systems. TBD 39717f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39727f3e84a1SEd Tanous systemName); 39737f3e84a1SEd Tanous return; 39747f3e84a1SEd Tanous } 397522d268cbSEd Tanous 3976253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 397722d268cbSEd Tanous { 397822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 397922d268cbSEd Tanous systemName); 398022d268cbSEd Tanous return; 398122d268cbSEd Tanous } 3982a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3983a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3984a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3985253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3986253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3987a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3988a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3989a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3990a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3991a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39923648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39935143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39943648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39957e860f15SJohn Edward Broadbent }); 3996a3316fc6SZhikuiRen } 3997a3316fc6SZhikuiRen 3998647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3999647b3cdcSGeorge Liu { 40000fda0f12SGeorge Liu BMCWEB_ROUTE( 40010fda0f12SGeorge Liu app, 400222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4003647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4004647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 400545ca1b86SEd Tanous [&app](const crow::Request& req, 4006647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 400722d268cbSEd Tanous const std::string& systemName, 4008647b3cdcSGeorge Liu const std::string& postCodeID) { 40093ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 401045ca1b86SEd Tanous { 401145ca1b86SEd Tanous return; 401245ca1b86SEd Tanous } 401372e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 401499351cd8SEd Tanous req.getHeaderValue("Accept"), 40154a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4016647b3cdcSGeorge Liu { 4017002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4018647b3cdcSGeorge Liu return; 4019647b3cdcSGeorge Liu } 402025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 40217f3e84a1SEd Tanous { 40227f3e84a1SEd Tanous // Option currently returns no systems. TBD 40237f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 40247f3e84a1SEd Tanous systemName); 40257f3e84a1SEd Tanous return; 40267f3e84a1SEd Tanous } 4027253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 402822d268cbSEd Tanous { 402922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 403022d268cbSEd Tanous systemName); 403122d268cbSEd Tanous return; 403222d268cbSEd Tanous } 4033647b3cdcSGeorge Liu 4034647b3cdcSGeorge Liu uint64_t currentValue = 0; 4035647b3cdcSGeorge Liu uint16_t index = 0; 4036647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4037647b3cdcSGeorge Liu { 4038002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4039647b3cdcSGeorge Liu return; 4040647b3cdcSGeorge Liu } 4041647b3cdcSGeorge Liu 4042647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4043647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 40445e7e2dc5SEd Tanous const boost::system::error_code& ec, 4045002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4046002d39b4SEd Tanous postcodes) { 4047647b3cdcSGeorge Liu if (ec.value() == EBADR) 4048647b3cdcSGeorge Liu { 4049002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4050002d39b4SEd Tanous postCodeID); 4051647b3cdcSGeorge Liu return; 4052647b3cdcSGeorge Liu } 4053647b3cdcSGeorge Liu if (ec) 4054647b3cdcSGeorge Liu { 405562598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4056647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4057647b3cdcSGeorge Liu return; 4058647b3cdcSGeorge Liu } 4059647b3cdcSGeorge Liu 4060647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4061002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4062647b3cdcSGeorge Liu { 406362598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4064002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4065002d39b4SEd Tanous postCodeID); 4066647b3cdcSGeorge Liu return; 4067647b3cdcSGeorge Liu } 4068647b3cdcSGeorge Liu 40699eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 407046ff87baSEd Tanous if (c.empty()) 4071647b3cdcSGeorge Liu { 407262598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4073002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4074002d39b4SEd Tanous postCodeID); 4075647b3cdcSGeorge Liu return; 4076647b3cdcSGeorge Liu } 407746ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 407846ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 407946ff87baSEd Tanous std::string_view strData(d, c.size()); 4080647b3cdcSGeorge Liu 4081d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4082647b3cdcSGeorge Liu "application/octet-stream"); 4083d9f6c621SEd Tanous asyncResp->res.addHeader( 4084d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 408527b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4086647b3cdcSGeorge Liu }, 4087647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4088647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4089002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4090647b3cdcSGeorge Liu }); 4091647b3cdcSGeorge Liu } 4092647b3cdcSGeorge Liu 40937e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4094a3316fc6SZhikuiRen { 40957e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 409622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4097ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 409945ca1b86SEd Tanous [&app](const crow::Request& req, 41007e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 410122d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 41023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 410345ca1b86SEd Tanous { 410445ca1b86SEd Tanous return; 410545ca1b86SEd Tanous } 410625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 41077f3e84a1SEd Tanous { 41087f3e84a1SEd Tanous // Option currently returns no systems. TBD 41097f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 41107f3e84a1SEd Tanous systemName); 41117f3e84a1SEd Tanous return; 41127f3e84a1SEd Tanous } 4113253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 411422d268cbSEd Tanous { 411522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 411622d268cbSEd Tanous systemName); 411722d268cbSEd Tanous return; 411822d268cbSEd Tanous } 411922d268cbSEd Tanous 41206f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 41217e860f15SJohn Edward Broadbent }); 4122a3316fc6SZhikuiRen } 4123a3316fc6SZhikuiRen 41241da66f75SEd Tanous } // namespace redfish 4125