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"; 380*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Description"] = 381*bd79bce8SPatrick Williams "Collection of " + dumpType + " 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 412*bd79bce8SPatrick Williams parseDumpEntryFromDbusObject(object, dumpStatus, size, 413*bd79bce8SPatrick Williams timestampUs, originatorId, 414*bd79bce8SPatrick Williams originatorType, 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"; 441*bd79bce8SPatrick Williams thisEntry["AdditionalDataURI"] = 442*bd79bce8SPatrick Williams entriesPath + entryID + "/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"; 449*bd79bce8SPatrick Williams thisEntry["AdditionalDataURI"] = 450*bd79bce8SPatrick Williams entriesPath + entryID + "/attachment"; 451fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 4525cb1dd27SAsmitha Karunanithi } 453b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 4545cb1dd27SAsmitha Karunanithi } 455*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 456*bd79bce8SPatrick Williams entriesArray.size(); 4573544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 4585eb468daSGeorge Liu }); 4595cb1dd27SAsmitha Karunanithi } 4605cb1dd27SAsmitha Karunanithi 4618d1b46d7Szhanghch05 inline void 462c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4638d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 4645cb1dd27SAsmitha Karunanithi { 465fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 466fdd26906SClaire Weinan if (entriesPath.empty()) 4675cb1dd27SAsmitha Karunanithi { 4685cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4695cb1dd27SAsmitha Karunanithi return; 4705cb1dd27SAsmitha Karunanithi } 4715cb1dd27SAsmitha Karunanithi 4725eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4735eb468daSGeorge Liu dbus::utility::getManagedObjects( 4745eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 475fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 4765e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 47702cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 4785cb1dd27SAsmitha Karunanithi if (ec) 4795cb1dd27SAsmitha Karunanithi { 48062598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 4815cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4825cb1dd27SAsmitha Karunanithi return; 4835cb1dd27SAsmitha Karunanithi } 4845cb1dd27SAsmitha Karunanithi 485b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 48618f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 487b47452b2SAsmitha Karunanithi 4889eb808c1SEd Tanous for (const auto& objectPath : resp) 4895cb1dd27SAsmitha Karunanithi { 490b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 4915cb1dd27SAsmitha Karunanithi { 4925cb1dd27SAsmitha Karunanithi continue; 4935cb1dd27SAsmitha Karunanithi } 4945cb1dd27SAsmitha Karunanithi 4955cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 496c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4975cb1dd27SAsmitha Karunanithi uint64_t size = 0; 49835440d18SAsmitha Karunanithi std::string dumpStatus; 49968dd075aSAsmitha Karunanithi std::string originatorId; 50068dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 50168dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 5025cb1dd27SAsmitha Karunanithi 503aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 50468dd075aSAsmitha Karunanithi timestampUs, originatorId, 50568dd075aSAsmitha Karunanithi originatorType, asyncResp); 5065cb1dd27SAsmitha Karunanithi 5070fda0f12SGeorge Liu if (dumpStatus != 5080fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 50935440d18SAsmitha Karunanithi !dumpStatus.empty()) 51035440d18SAsmitha Karunanithi { 51135440d18SAsmitha Karunanithi // Dump status is not Complete 51235440d18SAsmitha Karunanithi // return not found until status is changed to Completed 513*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 514*bd79bce8SPatrick Williams dumpType + " dump", entryID); 51535440d18SAsmitha Karunanithi return; 51635440d18SAsmitha Karunanithi } 51735440d18SAsmitha Karunanithi 5185cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 51968dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 520fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5215cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 5225cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 5235cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 524bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 525bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5265cb1dd27SAsmitha Karunanithi 52768dd075aSAsmitha Karunanithi if (!originatorId.empty()) 52868dd075aSAsmitha Karunanithi { 52968dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 53068dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 53168dd075aSAsmitha Karunanithi } 53268dd075aSAsmitha Karunanithi 5335cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5345cb1dd27SAsmitha Karunanithi { 535d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 536d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 537fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 538fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5395cb1dd27SAsmitha Karunanithi } 5405cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5415cb1dd27SAsmitha Karunanithi { 542d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 543*bd79bce8SPatrick Williams asyncResp->res.jsonValue["OEMDiagnosticDataType"] = 544*bd79bce8SPatrick Williams "System"; 545d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 546fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 547fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 5485cb1dd27SAsmitha Karunanithi } 5495cb1dd27SAsmitha Karunanithi } 550e05aec50SEd Tanous if (!foundDumpEntry) 551b47452b2SAsmitha Karunanithi { 55262598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 553b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 554b90d14f2SMyung Bae entryID); 555b47452b2SAsmitha Karunanithi return; 556b47452b2SAsmitha Karunanithi } 5575eb468daSGeorge Liu }); 5585cb1dd27SAsmitha Karunanithi } 5595cb1dd27SAsmitha Karunanithi 5608d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5619878256fSStanley Chu const std::string& entryID, 562b47452b2SAsmitha Karunanithi const std::string& dumpType) 5635cb1dd27SAsmitha Karunanithi { 5645a39f77aSPatrick Williams auto respHandler = [asyncResp, 5655a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 56662598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 5675cb1dd27SAsmitha Karunanithi if (ec) 5685cb1dd27SAsmitha Karunanithi { 5693de8d8baSGeorge Liu if (ec.value() == EBADR) 5703de8d8baSGeorge Liu { 5713de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 5723de8d8baSGeorge Liu return; 5733de8d8baSGeorge Liu } 57462598e31SEd Tanous BMCWEB_LOG_ERROR( 57562598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 57662598e31SEd Tanous entryID); 5775cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5785cb1dd27SAsmitha Karunanithi return; 5795cb1dd27SAsmitha Karunanithi } 5805cb1dd27SAsmitha Karunanithi }; 58118f8f608SEd Tanous 5825cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 5835cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 58418f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 5855cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 5865cb1dd27SAsmitha Karunanithi } 587b5f288d2SAbhilash Raju inline bool checkSizeLimit(int fd, crow::Response& res) 588b5f288d2SAbhilash Raju { 589b5f288d2SAbhilash Raju long long int size = lseek(fd, 0, SEEK_END); 590b5f288d2SAbhilash Raju if (size <= 0) 591b5f288d2SAbhilash Raju { 592b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 593b5f288d2SAbhilash Raju size); 594b5f288d2SAbhilash Raju messages::internalError(res); 595b5f288d2SAbhilash Raju return false; 596b5f288d2SAbhilash Raju } 5975cb1dd27SAsmitha Karunanithi 598b5f288d2SAbhilash Raju // Arbitrary max size of 20MB to accommodate BMC dumps 599b5f288d2SAbhilash Raju constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 600b5f288d2SAbhilash Raju if (size > maxFileSize) 601b5f288d2SAbhilash Raju { 602b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 603b5f288d2SAbhilash Raju size, maxFileSize); 604b5f288d2SAbhilash Raju messages::internalError(res); 605b5f288d2SAbhilash Raju return false; 606b5f288d2SAbhilash Raju } 607b5f288d2SAbhilash Raju off_t rc = lseek(fd, 0, SEEK_SET); 608b5f288d2SAbhilash Raju if (rc < 0) 609b5f288d2SAbhilash Raju { 610b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 611b5f288d2SAbhilash Raju messages::internalError(res); 612b5f288d2SAbhilash Raju return false; 613b5f288d2SAbhilash Raju } 614b5f288d2SAbhilash Raju return true; 615b5f288d2SAbhilash Raju } 616*bd79bce8SPatrick Williams inline void downloadEntryCallback( 617*bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 618*bd79bce8SPatrick Williams const std::string& entryID, const std::string& downloadEntryType, 619168d1b1aSCarson Labrado const boost::system::error_code& ec, 620168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 621168d1b1aSCarson Labrado { 622168d1b1aSCarson Labrado if (ec.value() == EBADR) 623168d1b1aSCarson Labrado { 624168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 625168d1b1aSCarson Labrado return; 626168d1b1aSCarson Labrado } 627168d1b1aSCarson Labrado if (ec) 628168d1b1aSCarson Labrado { 629168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 630168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 631168d1b1aSCarson Labrado return; 632168d1b1aSCarson Labrado } 633168d1b1aSCarson Labrado 634168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 635168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 636168d1b1aSCarson Labrado { 637168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 638168d1b1aSCarson Labrado downloadEntryType); 639168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 640168d1b1aSCarson Labrado } 641168d1b1aSCarson Labrado 642168d1b1aSCarson Labrado int fd = -1; 643168d1b1aSCarson Labrado fd = dup(unixfd); 644168d1b1aSCarson Labrado if (fd < 0) 645168d1b1aSCarson Labrado { 646168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 647168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 648168d1b1aSCarson Labrado return; 649168d1b1aSCarson Labrado } 650b5f288d2SAbhilash Raju if (!checkSizeLimit(fd, asyncResp->res)) 651168d1b1aSCarson Labrado { 652168d1b1aSCarson Labrado close(fd); 653168d1b1aSCarson Labrado return; 654168d1b1aSCarson Labrado } 655168d1b1aSCarson Labrado if (downloadEntryType == "System") 656168d1b1aSCarson Labrado { 657b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 658b5f288d2SAbhilash Raju { 659b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 660b5f288d2SAbhilash Raju close(fd); 661b5f288d2SAbhilash Raju return; 662b5f288d2SAbhilash Raju } 663168d1b1aSCarson Labrado asyncResp->res.addHeader( 664168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 665b5f288d2SAbhilash Raju return; 666168d1b1aSCarson Labrado } 667b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd)) 66827b0cf90SEd Tanous { 669b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 670b5f288d2SAbhilash Raju close(fd); 671b5f288d2SAbhilash Raju return; 67227b0cf90SEd Tanous } 673168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 674168d1b1aSCarson Labrado "application/octet-stream"); 675168d1b1aSCarson Labrado } 676168d1b1aSCarson Labrado 677168d1b1aSCarson Labrado inline void 678168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 679168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 680168d1b1aSCarson Labrado { 681168d1b1aSCarson Labrado if (dumpType != "BMC") 682168d1b1aSCarson Labrado { 683168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 684168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 685168d1b1aSCarson Labrado return; 686168d1b1aSCarson Labrado } 687168d1b1aSCarson Labrado 688*bd79bce8SPatrick Williams std::string dumpEntryPath = 689*bd79bce8SPatrick Williams std::format("{}/entry/{}", getDumpPath(dumpType), entryID); 690168d1b1aSCarson Labrado 691168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 692168d1b1aSCarson Labrado [asyncResp, entryID, 693168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 694168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 695168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 696168d1b1aSCarson Labrado }; 697168d1b1aSCarson Labrado 698168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 699168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 700168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 701168d1b1aSCarson Labrado } 702168d1b1aSCarson Labrado 703*bd79bce8SPatrick Williams inline void downloadEventLogEntry( 704*bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 705*bd79bce8SPatrick Williams const std::string& systemName, 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 { 839*bd79bce8SPatrick Williams const char* thisInterfaceName = 840*bd79bce8SPatrick Williams interfaceNode->Attribute("name"); 8418e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 8428e31778eSAsmitha Karunanithi { 8438e31778eSAsmitha Karunanithi if (thisInterfaceName == 8448e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 8458e31778eSAsmitha Karunanithi { 8468e31778eSAsmitha Karunanithi interfaceNode = 8478e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 8488e31778eSAsmitha Karunanithi continue; 8498e31778eSAsmitha Karunanithi } 8508e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 8518e31778eSAsmitha Karunanithi break; 8528e31778eSAsmitha Karunanithi } 8538e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 8548e31778eSAsmitha Karunanithi } 8558e31778eSAsmitha Karunanithi 856a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 8578e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 858*bd79bce8SPatrick Williams const boost::system::error_code& ec2, 859*bd79bce8SPatrick Williams sdbusplus::message_t& msg, 860a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 8618b24275dSEd Tanous if (ec2) 862cb13a392SEd Tanous { 86362598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 86462598e31SEd Tanous createdObjPath.str); 865*bd79bce8SPatrick Williams taskData->messages.emplace_back( 866*bd79bce8SPatrick Williams messages::internalError()); 8676145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 8686145ed6fSAsmitha Karunanithi return task::completed; 869cb13a392SEd Tanous } 870b9d36b47SEd Tanous 8718e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 872a43be80fSAsmitha Karunanithi { 8738e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8748e31778eSAsmitha Karunanithi std::string prop; 8758e31778eSAsmitha Karunanithi msg.read(prop, values); 8768e31778eSAsmitha Karunanithi 8778e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8788e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 879*bd79bce8SPatrick Williams if (dumpStatus == 880*bd79bce8SPatrick Williams DumpCreationProgress::DUMP_CREATE_FAILED) 8818e31778eSAsmitha Karunanithi { 88262598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 88362598e31SEd Tanous createdObjPath.str); 8848e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8858e31778eSAsmitha Karunanithi return task::completed; 8868e31778eSAsmitha Karunanithi } 8878e31778eSAsmitha Karunanithi 888*bd79bce8SPatrick Williams if (dumpStatus == 889*bd79bce8SPatrick Williams DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8908e31778eSAsmitha Karunanithi { 891*bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG( 892*bd79bce8SPatrick Williams "{}: Dump creation task is in progress", 89362598e31SEd Tanous createdObjPath.str); 8948e31778eSAsmitha Karunanithi return !task::completed; 8958e31778eSAsmitha Karunanithi } 8968e31778eSAsmitha Karunanithi } 8978e31778eSAsmitha Karunanithi 898a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 899a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 900a43be80fSAsmitha Karunanithi 901c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 902253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump/Entries/{}", 903253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, dumpId); 904c51a58eeSEd Tanous 905c51a58eeSEd Tanous std::string headerLoc = "Location: "; 906c51a58eeSEd Tanous headerLoc += url.buffer(); 907c51a58eeSEd Tanous 908*bd79bce8SPatrick Williams taskData->payload->httpHeaders.emplace_back( 909*bd79bce8SPatrick Williams std::move(headerLoc)); 910a43be80fSAsmitha Karunanithi 91162598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 91262598e31SEd Tanous createdObjPath.str); 913a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 914b47452b2SAsmitha Karunanithi return task::completed; 915a43be80fSAsmitha Karunanithi }, 9168e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 9178e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 9188e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 919a43be80fSAsmitha Karunanithi 9208e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 9218e31778eSAsmitha Karunanithi // requested dump will be collected. 9228e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 923a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 9248e31778eSAsmitha Karunanithi task->payload.emplace(payload); 9258e31778eSAsmitha Karunanithi }, 9268e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 9278e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 928a43be80fSAsmitha Karunanithi } 929a43be80fSAsmitha Karunanithi 9308d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9318d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 932a43be80fSAsmitha Karunanithi { 933fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 934fdd26906SClaire Weinan if (dumpPath.empty()) 935a43be80fSAsmitha Karunanithi { 936a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 937a43be80fSAsmitha Karunanithi return; 938a43be80fSAsmitha Karunanithi } 939a43be80fSAsmitha Karunanithi 940a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 941a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 942a43be80fSAsmitha Karunanithi 94315ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 944a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 945a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 946a43be80fSAsmitha Karunanithi { 947a43be80fSAsmitha Karunanithi return; 948a43be80fSAsmitha Karunanithi } 949a43be80fSAsmitha Karunanithi 950a43be80fSAsmitha Karunanithi if (dumpType == "System") 951a43be80fSAsmitha Karunanithi { 952a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 953a43be80fSAsmitha Karunanithi { 95462598e31SEd Tanous BMCWEB_LOG_ERROR( 95562598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 956a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 957a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 958a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 959a43be80fSAsmitha Karunanithi return; 960a43be80fSAsmitha Karunanithi } 9613174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 962a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 963a43be80fSAsmitha Karunanithi { 96462598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 965ace85d60SEd Tanous messages::internalError(asyncResp->res); 966a43be80fSAsmitha Karunanithi return; 967a43be80fSAsmitha Karunanithi } 968253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump/", 969253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 970a43be80fSAsmitha Karunanithi } 971a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 972a43be80fSAsmitha Karunanithi { 973a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 974a43be80fSAsmitha Karunanithi { 97562598e31SEd Tanous BMCWEB_LOG_ERROR( 97662598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 977a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 978a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 979a43be80fSAsmitha Karunanithi return; 980a43be80fSAsmitha Karunanithi } 9813174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 982a43be80fSAsmitha Karunanithi { 98362598e31SEd Tanous BMCWEB_LOG_ERROR( 98462598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 985ace85d60SEd Tanous messages::internalError(asyncResp->res); 986a43be80fSAsmitha Karunanithi return; 987a43be80fSAsmitha Karunanithi } 988253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump/", 989253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 9905907571dSAsmitha Karunanithi } 9915907571dSAsmitha Karunanithi else 9925907571dSAsmitha Karunanithi { 99362598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 9945907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9955907571dSAsmitha Karunanithi return; 996a43be80fSAsmitha Karunanithi } 997a43be80fSAsmitha Karunanithi 9988e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9998e31778eSAsmitha Karunanithi createDumpParamVec; 10008e31778eSAsmitha Karunanithi 1001f574a8e1SCarson Labrado if (req.session != nullptr) 1002f574a8e1SCarson Labrado { 100368dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 100468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 100568dd075aSAsmitha Karunanithi req.session->clientIp); 100668dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 100768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 100868dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1009f574a8e1SCarson Labrado } 101068dd075aSAsmitha Karunanithi 1011a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 10125e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 10135e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 10145e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 10158e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1016a43be80fSAsmitha Karunanithi if (ec) 1017a43be80fSAsmitha Karunanithi { 101862598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 10195907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 10205907571dSAsmitha Karunanithi if (dbusError == nullptr) 10215907571dSAsmitha Karunanithi { 10225907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 10235907571dSAsmitha Karunanithi return; 10245907571dSAsmitha Karunanithi } 10255907571dSAsmitha Karunanithi 102662598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 102762598e31SEd Tanous dbusError->name, dbusError->message); 10285907571dSAsmitha Karunanithi if (std::string_view( 10295907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 10305907571dSAsmitha Karunanithi dbusError->name) 10315907571dSAsmitha Karunanithi { 10325907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 10335907571dSAsmitha Karunanithi return; 10345907571dSAsmitha Karunanithi } 10355907571dSAsmitha Karunanithi if (std::string_view( 10365907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 10375907571dSAsmitha Karunanithi dbusError->name) 10385907571dSAsmitha Karunanithi { 10395907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 10405907571dSAsmitha Karunanithi return; 10415907571dSAsmitha Karunanithi } 10425907571dSAsmitha Karunanithi if (std::string_view( 10435907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 10445907571dSAsmitha Karunanithi dbusError->name) 10455907571dSAsmitha Karunanithi { 10465907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 10475907571dSAsmitha Karunanithi return; 10485907571dSAsmitha Karunanithi } 10495907571dSAsmitha Karunanithi // Other Dbus errors such as: 10505907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 10515907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 10525907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 10535907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 10545907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 10555907571dSAsmitha Karunanithi // back to the client. 1056a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1057a43be80fSAsmitha Karunanithi return; 1058a43be80fSAsmitha Karunanithi } 105962598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 10608e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1061a43be80fSAsmitha Karunanithi }, 106218f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10638e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1064a43be80fSAsmitha Karunanithi } 1065a43be80fSAsmitha Karunanithi 10668d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10678d1b46d7Szhanghch05 const std::string& dumpType) 106880319af1SAsmitha Karunanithi { 10690d946211SClaire Weinan crow::connections::systemBus->async_method_call( 10700d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 107180319af1SAsmitha Karunanithi if (ec) 107280319af1SAsmitha Karunanithi { 107362598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 107480319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 107580319af1SAsmitha Karunanithi return; 107680319af1SAsmitha Karunanithi } 10770d946211SClaire Weinan }, 107818f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 10790d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 108080319af1SAsmitha Karunanithi } 108180319af1SAsmitha Karunanithi 1082*bd79bce8SPatrick Williams inline void parseCrashdumpParameters( 1083*bd79bce8SPatrick Williams const dbus::utility::DBusPropertiesMap& params, std::string& filename, 1084*bd79bce8SPatrick Williams std::string& timestamp, std::string& logfile) 1085043a0536SJohnathan Mantey { 1086d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1087d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1088d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1089d1bde9e5SKrzysztof Grobelny 1090d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1091d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1092d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1093d1bde9e5SKrzysztof Grobelny 1094d1bde9e5SKrzysztof Grobelny if (!success) 1095043a0536SJohnathan Mantey { 1096d1bde9e5SKrzysztof Grobelny return; 1097043a0536SJohnathan Mantey } 1098d1bde9e5SKrzysztof Grobelny 1099d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1100043a0536SJohnathan Mantey { 1101d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1102d1bde9e5SKrzysztof Grobelny } 1103d1bde9e5SKrzysztof Grobelny 1104d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1105043a0536SJohnathan Mantey { 1106d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1107043a0536SJohnathan Mantey } 1108d1bde9e5SKrzysztof Grobelny 1109d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1110043a0536SJohnathan Mantey { 1111d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1112043a0536SJohnathan Mantey } 1113043a0536SJohnathan Mantey } 1114043a0536SJohnathan Mantey 11157e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 11161da66f75SEd Tanous { 1117c4bf6374SJason M. Bills /** 1118c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1119c4bf6374SJason M. Bills */ 112022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1121ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1122*bd79bce8SPatrick Williams .methods( 1123*bd79bce8SPatrick Williams boost::beast::http::verb:: 1124*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 112522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 112622d268cbSEd Tanous const std::string& systemName) { 11273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1128c4bf6374SJason M. Bills { 112945ca1b86SEd Tanous return; 113045ca1b86SEd Tanous } 113125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 11327f3e84a1SEd Tanous { 11337f3e84a1SEd Tanous // Option currently returns no systems. TBD 11347f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 11357f3e84a1SEd Tanous systemName); 11367f3e84a1SEd Tanous return; 11377f3e84a1SEd Tanous } 1138253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 113922d268cbSEd Tanous { 114022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 114122d268cbSEd Tanous systemName); 114222d268cbSEd Tanous return; 114322d268cbSEd Tanous } 114422d268cbSEd Tanous 11457e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 11467e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1147c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1148c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1149c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1150253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices", 1151253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 115245ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1153c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1154c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1155*bd79bce8SPatrick Williams nlohmann::json& logServiceArray = 1156*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 1157c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11581476687dSEd Tanous nlohmann::json::object_t eventLog; 11591476687dSEd Tanous eventLog["@odata.id"] = 1160253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1161253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1162b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 116325b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 116425b54dbaSEd Tanous { 11651476687dSEd Tanous nlohmann::json::object_t dumpLog; 116625b54dbaSEd Tanous dumpLog["@odata.id"] = 1167253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump", 1168253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1169b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 117025b54dbaSEd Tanous } 1171c9bb6861Sraviteja-b 11725ffd11f2SGunnar Mills if constexpr (BMCWEB_REDFISH_CPU_LOG) 117325b54dbaSEd Tanous { 11741476687dSEd Tanous nlohmann::json::object_t crashdump; 11751476687dSEd Tanous crashdump["@odata.id"] = 1176253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 1177253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1178b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 117925b54dbaSEd Tanous } 1180b7028ebfSSpencer Ku 118125b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_HOST_LOGGER) 118225b54dbaSEd Tanous { 11831476687dSEd Tanous nlohmann::json::object_t hostlogger; 11841476687dSEd Tanous hostlogger["@odata.id"] = 1185253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 1186253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1187b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 118825b54dbaSEd Tanous } 1189c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1190c4bf6374SJason M. Bills logServiceArray.size(); 1191a3316fc6SZhikuiRen 11927a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11937a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11947a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11957a1dbc48SGeorge Liu "/", 0, interfaces, 11967a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1197b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1198b9d36b47SEd Tanous subtreePath) { 1199a3316fc6SZhikuiRen if (ec) 1200a3316fc6SZhikuiRen { 120162598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1202a3316fc6SZhikuiRen return; 1203a3316fc6SZhikuiRen } 1204a3316fc6SZhikuiRen 120555f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1206a3316fc6SZhikuiRen { 1207a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1208a3316fc6SZhikuiRen { 120923a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1210a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1211613dabeaSEd Tanous nlohmann::json::object_t member; 1212253f11b8SEd Tanous member["@odata.id"] = std::format( 1213253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes", 1214253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1215613dabeaSEd Tanous 1216*bd79bce8SPatrick Williams logServiceArrayLocal.emplace_back( 1217*bd79bce8SPatrick Williams std::move(member)); 1218613dabeaSEd Tanous 121945ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 122023a21a1cSEd Tanous logServiceArrayLocal.size(); 1221a3316fc6SZhikuiRen return; 1222a3316fc6SZhikuiRen } 1223a3316fc6SZhikuiRen } 12247a1dbc48SGeorge Liu }); 12257e860f15SJohn Edward Broadbent }); 1226c4bf6374SJason M. Bills } 1227c4bf6374SJason M. Bills 12287e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1229c4bf6374SJason M. Bills { 123022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1231ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1232*bd79bce8SPatrick Williams .methods( 1233*bd79bce8SPatrick Williams boost::beast::http::verb:: 1234*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 123522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 123622d268cbSEd Tanous const std::string& systemName) { 12373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 123845ca1b86SEd Tanous { 123945ca1b86SEd Tanous return; 124045ca1b86SEd Tanous } 1241253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 124222d268cbSEd Tanous { 124322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 124422d268cbSEd Tanous systemName); 124522d268cbSEd Tanous return; 124622d268cbSEd Tanous } 1247c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1248253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1249253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1250c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1251b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1252c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1253*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Description"] = 1254*bd79bce8SPatrick Williams "System Event Log Service"; 1255c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1256539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 1257539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 12587c8c4058STejas Patil 12597c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 12602b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 12617c8c4058STejas Patil 12627c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 12637c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 12647c8c4058STejas Patil redfishDateTimeOffset.second; 12657c8c4058STejas Patil 1266*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format( 1267*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1268253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1269*bd79bce8SPatrick Williams asyncResp->res 1270*bd79bce8SPatrick Williams .jsonValue["Actions"]["#LogService.ClearLog"]["target"] 1271e7d6c8b2SGunnar Mills 127220fa6a2cSEd Tanous = std::format( 1273253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog", 127420fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 12757e860f15SJohn Edward Broadbent }); 1276489640c6SJason M. Bills } 1277489640c6SJason M. Bills 1278599b9af3SAlexander Hansen inline void handleSystemsLogServicesEventLogActionsClearPost( 1279599b9af3SAlexander Hansen App& app, const crow::Request& req, 128022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1281599b9af3SAlexander Hansen const std::string& systemName) 1282599b9af3SAlexander Hansen { 12833ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 128445ca1b86SEd Tanous { 128545ca1b86SEd Tanous return; 128645ca1b86SEd Tanous } 1287253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 128822d268cbSEd Tanous { 128922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 129022d268cbSEd Tanous systemName); 129122d268cbSEd Tanous return; 129222d268cbSEd Tanous } 1293599b9af3SAlexander Hansen 1294489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1295489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1296489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1297489640c6SJason M. Bills { 1298489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1299489640c6SJason M. Bills { 1300489640c6SJason M. Bills std::error_code ec; 1301489640c6SJason M. Bills std::filesystem::remove(file, ec); 1302489640c6SJason M. Bills } 1303489640c6SJason M. Bills } 1304489640c6SJason M. Bills 1305489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1306489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 13075e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1308489640c6SJason M. Bills if (ec) 1309489640c6SJason M. Bills { 131062598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1311489640c6SJason M. Bills messages::internalError(asyncResp->res); 1312489640c6SJason M. Bills return; 1313489640c6SJason M. Bills } 1314489640c6SJason M. Bills 1315489640c6SJason M. Bills messages::success(asyncResp->res); 1316489640c6SJason M. Bills }, 1317489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1318002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1319002d39b4SEd Tanous "replace"); 1320599b9af3SAlexander Hansen } 1321599b9af3SAlexander Hansen 1322599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogClear(App& app) 1323599b9af3SAlexander Hansen { 1324599b9af3SAlexander Hansen BMCWEB_ROUTE( 1325599b9af3SAlexander Hansen app, 1326599b9af3SAlexander Hansen "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1327599b9af3SAlexander Hansen .privileges({{"ConfigureComponents"}}) 1328599b9af3SAlexander Hansen .methods(boost::beast::http::verb::post)(std::bind_front( 1329599b9af3SAlexander Hansen handleSystemsLogServicesEventLogActionsClearPost, std::ref(app))); 1330c4bf6374SJason M. Bills } 1331c4bf6374SJason M. Bills 1332ac992cdeSJason M. Bills enum class LogParseError 1333ac992cdeSJason M. Bills { 1334ac992cdeSJason M. Bills success, 1335ac992cdeSJason M. Bills parseFailed, 1336ac992cdeSJason M. Bills messageIdNotInRegistry, 1337ac992cdeSJason M. Bills }; 1338ac992cdeSJason M. Bills 1339*bd79bce8SPatrick Williams static LogParseError fillEventLogEntryJson( 1340*bd79bce8SPatrick Williams const std::string& logEntryID, const std::string& logEntry, 1341de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1342c4bf6374SJason M. Bills { 134395820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1344cd225da8SJason M. Bills // First get the Timestamp 1345f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1346cd225da8SJason M. Bills if (space == std::string::npos) 134795820184SJason M. Bills { 1348ac992cdeSJason M. Bills return LogParseError::parseFailed; 134995820184SJason M. Bills } 1350cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1351cd225da8SJason M. Bills // Then get the log contents 1352f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1353cd225da8SJason M. Bills if (entryStart == std::string::npos) 1354cd225da8SJason M. Bills { 1355ac992cdeSJason M. Bills return LogParseError::parseFailed; 1356cd225da8SJason M. Bills } 1357cd225da8SJason M. Bills std::string_view entry(logEntry); 1358cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1359cd225da8SJason M. Bills // Use split to separate the entry into its fields 1360cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 136150ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1362cd225da8SJason M. Bills // We need at least a MessageId to be valid 13631e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 13641e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1365cd225da8SJason M. Bills { 1366ac992cdeSJason M. Bills return LogParseError::parseFailed; 1367cd225da8SJason M. Bills } 13681e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 13694851d45dSJason M. Bills // Get the Message from the MessageRegistry 1370fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1371c4bf6374SJason M. Bills 13721e6deaf6SEd Tanous logEntryIter++; 137354417b02SSui Chen if (message == nullptr) 1374c4bf6374SJason M. Bills { 137562598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1376ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1377c4bf6374SJason M. Bills } 1378c4bf6374SJason M. Bills 13791e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 13801e6deaf6SEd Tanous logEntryFields.end()); 1381c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1382c05bba45SEd Tanous 1383*bd79bce8SPatrick Williams std::string msg = 1384*bd79bce8SPatrick Williams redfish::registries::fillMessageArgs(messageArgs, message->message); 13851e6deaf6SEd Tanous if (msg.empty()) 138615a86ff6SJason M. Bills { 13871e6deaf6SEd Tanous return LogParseError::parseFailed; 138815a86ff6SJason M. Bills } 13894851d45dSJason M. Bills 139095820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 139195820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 139295820184SJason M. Bills // between the '.' and the '+', so just remove them. 1393f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1394f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 139595820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1396c4bf6374SJason M. Bills { 139795820184SJason M. Bills timestamp.erase(dot, plus - dot); 1398c4bf6374SJason M. Bills } 1399c4bf6374SJason M. Bills 1400c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 14019c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1402ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1403253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1404253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 140584afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 140684afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 140784afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 140884afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 140984afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 141084afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 141184afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 141284afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1413ac992cdeSJason M. Bills return LogParseError::success; 1414c4bf6374SJason M. Bills } 1415c4bf6374SJason M. Bills 1416898f2aa2SEd Tanous inline void fillEventLogLogEntryFromPropertyMap( 1417898f2aa2SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1418898f2aa2SEd Tanous const dbus::utility::DBusPropertiesMap& resp, 1419898f2aa2SEd Tanous nlohmann::json& objectToFillOut) 1420898f2aa2SEd Tanous { 1421898f2aa2SEd Tanous uint32_t id = 0; 1422898f2aa2SEd Tanous uint64_t timestamp = 0; 1423898f2aa2SEd Tanous uint64_t updateTimestamp = 0; 1424898f2aa2SEd Tanous std::string severity; 1425898f2aa2SEd Tanous std::string message; 1426898f2aa2SEd Tanous const std::string* filePath = nullptr; 1427898f2aa2SEd Tanous const std::string* resolution = nullptr; 1428898f2aa2SEd Tanous bool resolved = false; 1429898f2aa2SEd Tanous std::string notify; 1430898f2aa2SEd Tanous // clang-format off 1431898f2aa2SEd Tanous bool success = sdbusplus::unpackPropertiesNoThrow( 1432898f2aa2SEd Tanous dbus_utils::UnpackErrorPrinter(), resp, 1433898f2aa2SEd Tanous "Id", id, 1434898f2aa2SEd Tanous "Message", message, 1435898f2aa2SEd Tanous "Path", filePath, 1436898f2aa2SEd Tanous "Resolution", resolution, 1437898f2aa2SEd Tanous "Resolved", resolved, 1438898f2aa2SEd Tanous "ServiceProviderNotify", notify, 1439898f2aa2SEd Tanous "Severity", severity, 1440898f2aa2SEd Tanous "Timestamp", timestamp, 1441898f2aa2SEd Tanous "UpdateTimestamp", updateTimestamp 1442898f2aa2SEd Tanous ); 1443898f2aa2SEd Tanous // clang-format on 1444898f2aa2SEd Tanous 1445898f2aa2SEd Tanous if (!success) 1446898f2aa2SEd Tanous { 1447898f2aa2SEd Tanous messages::internalError(asyncResp->res); 1448898f2aa2SEd Tanous return; 1449898f2aa2SEd Tanous } 1450898f2aa2SEd Tanous 1451898f2aa2SEd Tanous objectToFillOut["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1452898f2aa2SEd Tanous objectToFillOut["@odata.id"] = boost::urls::format( 1453898f2aa2SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1454898f2aa2SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(id)); 1455898f2aa2SEd Tanous objectToFillOut["Name"] = "System Event Log Entry"; 1456898f2aa2SEd Tanous objectToFillOut["Id"] = std::to_string(id); 1457898f2aa2SEd Tanous objectToFillOut["Message"] = message; 1458898f2aa2SEd Tanous objectToFillOut["Resolved"] = resolved; 1459898f2aa2SEd Tanous std::optional<bool> notifyAction = getProviderNotifyAction(notify); 1460898f2aa2SEd Tanous if (notifyAction) 1461898f2aa2SEd Tanous { 1462898f2aa2SEd Tanous objectToFillOut["ServiceProviderNotified"] = *notifyAction; 1463898f2aa2SEd Tanous } 1464898f2aa2SEd Tanous if ((resolution != nullptr) && !resolution->empty()) 1465898f2aa2SEd Tanous { 1466898f2aa2SEd Tanous objectToFillOut["Resolution"] = *resolution; 1467898f2aa2SEd Tanous } 1468898f2aa2SEd Tanous objectToFillOut["EntryType"] = "Event"; 1469898f2aa2SEd Tanous objectToFillOut["Severity"] = translateSeverityDbusToRedfish(severity); 1470898f2aa2SEd Tanous objectToFillOut["Created"] = 1471898f2aa2SEd Tanous redfish::time_utils::getDateTimeUintMs(timestamp); 1472898f2aa2SEd Tanous objectToFillOut["Modified"] = 1473898f2aa2SEd Tanous redfish::time_utils::getDateTimeUintMs(updateTimestamp); 1474898f2aa2SEd Tanous if (filePath != nullptr) 1475898f2aa2SEd Tanous { 1476898f2aa2SEd Tanous objectToFillOut["AdditionalDataURI"] = boost::urls::format( 1477898f2aa2SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}/attachment", 1478898f2aa2SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(id)); 1479898f2aa2SEd Tanous } 1480898f2aa2SEd Tanous } 1481898f2aa2SEd Tanous 1482b729096dSEd Tanous inline void afterLogEntriesGetManagedObjects( 1483b729096dSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1484b729096dSEd Tanous const boost::system::error_code& ec, 1485b729096dSEd Tanous const dbus::utility::ManagedObjectType& resp) 1486b729096dSEd Tanous { 1487b729096dSEd Tanous if (ec) 1488b729096dSEd Tanous { 1489b729096dSEd Tanous // TODO Handle for specific error code 1490b729096dSEd Tanous BMCWEB_LOG_ERROR("getLogEntriesIfaceData resp_handler got error {}", 1491b729096dSEd Tanous ec); 1492b729096dSEd Tanous messages::internalError(asyncResp->res); 1493b729096dSEd Tanous return; 1494b729096dSEd Tanous } 1495b729096dSEd Tanous nlohmann::json::array_t entriesArray; 1496b729096dSEd Tanous for (const auto& objectPath : resp) 1497b729096dSEd Tanous { 1498898f2aa2SEd Tanous dbus::utility::DBusPropertiesMap propsFlattened; 1499*bd79bce8SPatrick Williams auto isEntry = 1500*bd79bce8SPatrick Williams std::ranges::find_if(objectPath.second, [](const auto& object) { 1501898f2aa2SEd Tanous return object.first == "xyz.openbmc_project.Logging.Entry"; 1502898f2aa2SEd Tanous }); 1503898f2aa2SEd Tanous if (isEntry == objectPath.second.end()) 1504b729096dSEd Tanous { 1505b729096dSEd Tanous continue; 1506b729096dSEd Tanous } 1507898f2aa2SEd Tanous for (const auto& interfaceMap : objectPath.second) 1508b729096dSEd Tanous { 1509898f2aa2SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1510b729096dSEd Tanous { 1511898f2aa2SEd Tanous propsFlattened.emplace_back(propertyMap.first, 1512898f2aa2SEd Tanous propertyMap.second); 1513b729096dSEd Tanous } 1514b729096dSEd Tanous } 1515898f2aa2SEd Tanous fillEventLogLogEntryFromPropertyMap(asyncResp, propsFlattened, 1516898f2aa2SEd Tanous entriesArray.emplace_back()); 1517b729096dSEd Tanous } 1518898f2aa2SEd Tanous 1519b729096dSEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 1520b729096dSEd Tanous const nlohmann::json& right) { 1521b729096dSEd Tanous return (left["Id"] <= right["Id"]); 1522b729096dSEd Tanous }); 1523b729096dSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 1524b729096dSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 1525b729096dSEd Tanous } 1526b729096dSEd Tanous 1527599b9af3SAlexander Hansen inline void handleSystemsLogServiceEventLogLogEntryCollection( 1528599b9af3SAlexander Hansen App& app, const crow::Request& req, 152922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1530599b9af3SAlexander Hansen const std::string& systemName) 1531599b9af3SAlexander Hansen { 1532c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1533c937d2bfSEd Tanous .canDelegateTop = true, 1534c937d2bfSEd Tanous .canDelegateSkip = true, 1535c937d2bfSEd Tanous }; 1536c937d2bfSEd Tanous query_param::Query delegatedQuery; 1537599b9af3SAlexander Hansen if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp, 1538599b9af3SAlexander Hansen delegatedQuery, capabilities)) 1539c4bf6374SJason M. Bills { 1540c4bf6374SJason M. Bills return; 1541c4bf6374SJason M. Bills } 154225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 15437f3e84a1SEd Tanous { 15447f3e84a1SEd Tanous // Option currently returns no systems. TBD 15457f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15467f3e84a1SEd Tanous systemName); 15477f3e84a1SEd Tanous return; 15487f3e84a1SEd Tanous } 1549253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 155022d268cbSEd Tanous { 155122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 155222d268cbSEd Tanous systemName); 155322d268cbSEd Tanous return; 155422d268cbSEd Tanous } 155522d268cbSEd Tanous 15565143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15573648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 15583648c8beSEd Tanous 15597e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15607e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1561c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1562c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1563c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1564253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1565253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1566c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1567c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1568c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1569cb92c03bSAndrew Geissler 15704978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1571c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 15727e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 15737e860f15SJohn Edward Broadbent // entry 157495820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 157595820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1576b01bf299SEd Tanous uint64_t entryCount = 0; 1577cd225da8SJason M. Bills std::string logEntry; 157895820184SJason M. Bills 15797e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15807e860f15SJohn Edward Broadbent // backwards 1581599b9af3SAlexander Hansen for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++) 1582c4bf6374SJason M. Bills { 1583cd225da8SJason M. Bills std::ifstream logStream(*it); 158495820184SJason M. Bills if (!logStream.is_open()) 1585c4bf6374SJason M. Bills { 1586c4bf6374SJason M. Bills continue; 1587c4bf6374SJason M. Bills } 1588c4bf6374SJason M. Bills 1589e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1590e85d6b16SJason M. Bills bool firstEntry = true; 159195820184SJason M. Bills while (std::getline(logStream, logEntry)) 159295820184SJason M. Bills { 1593c4bf6374SJason M. Bills std::string idStr; 1594e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1595c4bf6374SJason M. Bills { 1596c4bf6374SJason M. Bills continue; 1597c4bf6374SJason M. Bills } 1598e85d6b16SJason M. Bills firstEntry = false; 1599e85d6b16SJason M. Bills 1600de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1601*bd79bce8SPatrick Williams LogParseError status = 1602*bd79bce8SPatrick Williams fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1603ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1604ac992cdeSJason M. Bills { 1605ac992cdeSJason M. Bills continue; 1606ac992cdeSJason M. Bills } 1607ac992cdeSJason M. Bills if (status != LogParseError::success) 1608c4bf6374SJason M. Bills { 1609c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1610c4bf6374SJason M. Bills return; 1611c4bf6374SJason M. Bills } 1612de703c5dSJason M. Bills 1613de703c5dSJason M. Bills entryCount++; 1614de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1615de703c5dSJason M. Bills // start) and top (number of entries to display) 16163648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1617de703c5dSJason M. Bills { 1618de703c5dSJason M. Bills continue; 1619de703c5dSJason M. Bills } 1620de703c5dSJason M. Bills 1621b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1622c4bf6374SJason M. Bills } 162395820184SJason M. Bills } 1624c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16253648c8beSEd Tanous if (skip + top < entryCount) 1626c4bf6374SJason M. Bills { 1627599b9af3SAlexander Hansen asyncResp->res.jsonValue["Members@odata.nextLink"] = 1628599b9af3SAlexander Hansen boost::urls::format( 1629253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}", 1630253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top)); 1631c4bf6374SJason M. Bills } 1632897967deSJason M. Bills } 1633897967deSJason M. Bills 1634599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogEntryCollection(App& app) 1635897967deSJason M. Bills { 1636599b9af3SAlexander Hansen BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1637599b9af3SAlexander Hansen .privileges(redfish::privileges::getLogEntryCollection) 1638599b9af3SAlexander Hansen .methods(boost::beast::http::verb::get)(std::bind_front( 1639599b9af3SAlexander Hansen handleSystemsLogServiceEventLogLogEntryCollection, std::ref(app))); 1640599b9af3SAlexander Hansen } 1641599b9af3SAlexander Hansen 1642599b9af3SAlexander Hansen inline void handleSystemsLogServiceEventLogEntriesGet( 1643599b9af3SAlexander Hansen App& app, const crow::Request& req, 16447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1645599b9af3SAlexander Hansen const std::string& systemName, const std::string& param) 1646599b9af3SAlexander Hansen { 16473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 164845ca1b86SEd Tanous { 164945ca1b86SEd Tanous return; 165045ca1b86SEd Tanous } 165125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 16527f3e84a1SEd Tanous { 16537f3e84a1SEd Tanous // Option currently returns no systems. TBD 16547f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16557f3e84a1SEd Tanous systemName); 16567f3e84a1SEd Tanous return; 16577f3e84a1SEd Tanous } 165822d268cbSEd Tanous 1659253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 166022d268cbSEd Tanous { 166122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 166222d268cbSEd Tanous systemName); 166322d268cbSEd Tanous return; 166422d268cbSEd Tanous } 166522d268cbSEd Tanous 16667e860f15SJohn Edward Broadbent const std::string& targetID = param; 16678d1b46d7Szhanghch05 16687e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 16697e860f15SJohn Edward Broadbent // entry to find the target entry 1670897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1671897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1672897967deSJason M. Bills std::string logEntry; 1673897967deSJason M. Bills 16747e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16757e860f15SJohn Edward Broadbent // backwards 1676599b9af3SAlexander Hansen for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++) 1677897967deSJason M. Bills { 1678897967deSJason M. Bills std::ifstream logStream(*it); 1679897967deSJason M. Bills if (!logStream.is_open()) 1680897967deSJason M. Bills { 1681897967deSJason M. Bills continue; 1682897967deSJason M. Bills } 1683897967deSJason M. Bills 1684897967deSJason M. Bills // Reset the unique ID on the first entry 1685897967deSJason M. Bills bool firstEntry = true; 1686897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1687897967deSJason M. Bills { 1688897967deSJason M. Bills std::string idStr; 1689897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1690897967deSJason M. Bills { 1691897967deSJason M. Bills continue; 1692897967deSJason M. Bills } 1693897967deSJason M. Bills firstEntry = false; 1694897967deSJason M. Bills 1695897967deSJason M. Bills if (idStr == targetID) 1696897967deSJason M. Bills { 1697de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1698*bd79bce8SPatrick Williams LogParseError status = 1699*bd79bce8SPatrick Williams fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1700ac992cdeSJason M. Bills if (status != LogParseError::success) 1701897967deSJason M. Bills { 1702897967deSJason M. Bills messages::internalError(asyncResp->res); 1703897967deSJason M. Bills return; 1704897967deSJason M. Bills } 1705d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1706897967deSJason M. Bills return; 1707897967deSJason M. Bills } 1708897967deSJason M. Bills } 1709897967deSJason M. Bills } 1710897967deSJason M. Bills // Requested ID was not found 17119db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 1712599b9af3SAlexander Hansen } 1713599b9af3SAlexander Hansen 1714599b9af3SAlexander Hansen inline void requestRoutesJournalEventLogEntry(App& app) 1715599b9af3SAlexander Hansen { 1716599b9af3SAlexander Hansen BMCWEB_ROUTE( 1717599b9af3SAlexander Hansen app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1718599b9af3SAlexander Hansen .privileges(redfish::privileges::getLogEntry) 1719599b9af3SAlexander Hansen .methods(boost::beast::http::verb::get)(std::bind_front( 1720599b9af3SAlexander Hansen handleSystemsLogServiceEventLogEntriesGet, std::ref(app))); 1721599b9af3SAlexander Hansen } 1722599b9af3SAlexander Hansen 1723599b9af3SAlexander Hansen inline void dBusEventLogEntryCollection( 1724599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1725599b9af3SAlexander Hansen { 1726599b9af3SAlexander Hansen // Collections don't include the static data added by SubRoute 1727599b9af3SAlexander Hansen // because it has a duplicate entry for members 1728599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.type"] = 1729599b9af3SAlexander Hansen "#LogEntryCollection.LogEntryCollection"; 1730599b9af3SAlexander Hansen asyncResp->res.jsonValue["@odata.id"] = 1731599b9af3SAlexander Hansen std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1732599b9af3SAlexander Hansen BMCWEB_REDFISH_SYSTEM_URI_NAME); 1733599b9af3SAlexander Hansen asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1734599b9af3SAlexander Hansen asyncResp->res.jsonValue["Description"] = 1735599b9af3SAlexander Hansen "Collection of System Event Log Entries"; 1736599b9af3SAlexander Hansen 1737599b9af3SAlexander Hansen // DBus implementation of EventLog/Entries 1738599b9af3SAlexander Hansen // Make call to Logging Service to find all log entry objects 1739599b9af3SAlexander Hansen sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 1740599b9af3SAlexander Hansen dbus::utility::getManagedObjects( 1741599b9af3SAlexander Hansen "xyz.openbmc_project.Logging", path, 1742599b9af3SAlexander Hansen [asyncResp](const boost::system::error_code& ec, 1743599b9af3SAlexander Hansen const dbus::utility::ManagedObjectType& resp) { 1744b729096dSEd Tanous afterLogEntriesGetManagedObjects(asyncResp, ec, resp); 17457e860f15SJohn Edward Broadbent }); 174608a4e4b5SAnthony Wilson } 174708a4e4b5SAnthony Wilson 17487e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 174908a4e4b5SAnthony Wilson { 175022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1751ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1752002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1753002d39b4SEd Tanous [&app](const crow::Request& req, 175422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 175522d268cbSEd Tanous const std::string& systemName) { 17563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 175745ca1b86SEd Tanous { 175845ca1b86SEd Tanous return; 175945ca1b86SEd Tanous } 176025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 17617f3e84a1SEd Tanous { 17627f3e84a1SEd Tanous // Option currently returns no systems. TBD 17637f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17647f3e84a1SEd Tanous systemName); 17657f3e84a1SEd Tanous return; 17667f3e84a1SEd Tanous } 1767253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 176822d268cbSEd Tanous { 176922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 177022d268cbSEd Tanous systemName); 177122d268cbSEd Tanous return; 177222d268cbSEd Tanous } 1773599b9af3SAlexander Hansen dBusEventLogEntryCollection(asyncResp); 1774599b9af3SAlexander Hansen }); 1775599b9af3SAlexander Hansen } 177622d268cbSEd Tanous 1777*bd79bce8SPatrick Williams inline void dBusEventLogEntryGet( 1778*bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string entryID) 1779599b9af3SAlexander Hansen { 1780599b9af3SAlexander Hansen dbus::utility::escapePathForDbus(entryID); 178108a4e4b5SAnthony Wilson 1782cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1783cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1784599b9af3SAlexander Hansen sdbusplus::asio::getAllProperties( 1785599b9af3SAlexander Hansen *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1786599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryID, "", 1787599b9af3SAlexander Hansen [asyncResp, entryID](const boost::system::error_code& ec, 1788599b9af3SAlexander Hansen const dbus::utility::DBusPropertiesMap& resp) { 1789599b9af3SAlexander Hansen if (ec.value() == EBADR) 1790599b9af3SAlexander Hansen { 1791599b9af3SAlexander Hansen messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1792599b9af3SAlexander Hansen entryID); 1793599b9af3SAlexander Hansen return; 1794599b9af3SAlexander Hansen } 1795cb92c03bSAndrew Geissler if (ec) 1796cb92c03bSAndrew Geissler { 1797*bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 1798*bd79bce8SPatrick Williams "EventLogEntry (DBus) resp_handler got error {}", ec); 1799cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1800cb92c03bSAndrew Geissler return; 1801cb92c03bSAndrew Geissler } 18029017faf2SAbhishek Patel 1803898f2aa2SEd Tanous fillEventLogLogEntryFromPropertyMap(asyncResp, resp, 1804898f2aa2SEd Tanous asyncResp->res.jsonValue); 1805599b9af3SAlexander Hansen }); 18067e860f15SJohn Edward Broadbent } 1807599b9af3SAlexander Hansen 1808599b9af3SAlexander Hansen inline void 1809599b9af3SAlexander Hansen dBusEventLogEntryPatch(const crow::Request& req, 1810599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1811599b9af3SAlexander Hansen const std::string& entryId) 1812599b9af3SAlexander Hansen { 1813599b9af3SAlexander Hansen std::optional<bool> resolved; 1814599b9af3SAlexander Hansen 1815599b9af3SAlexander Hansen if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", resolved)) 1816599b9af3SAlexander Hansen { 1817599b9af3SAlexander Hansen return; 1818599b9af3SAlexander Hansen } 1819599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Set Resolved"); 1820599b9af3SAlexander Hansen 1821599b9af3SAlexander Hansen setDbusProperty(asyncResp, "Resolved", "xyz.openbmc_project.Logging", 1822599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryId, 1823599b9af3SAlexander Hansen "xyz.openbmc_project.Logging.Entry", "Resolved", 1824599b9af3SAlexander Hansen resolved.value_or(false)); 1825599b9af3SAlexander Hansen } 1826599b9af3SAlexander Hansen 1827*bd79bce8SPatrick Williams inline void dBusEventLogEntryDelete( 1828*bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string entryID) 1829599b9af3SAlexander Hansen { 1830599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Do delete single event entries."); 1831599b9af3SAlexander Hansen 1832599b9af3SAlexander Hansen dbus::utility::escapePathForDbus(entryID); 1833599b9af3SAlexander Hansen 1834599b9af3SAlexander Hansen // Process response from Logging service. 1835599b9af3SAlexander Hansen auto respHandler = [asyncResp, 1836599b9af3SAlexander Hansen entryID](const boost::system::error_code& ec) { 1837599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 1838599b9af3SAlexander Hansen if (ec) 1839599b9af3SAlexander Hansen { 1840599b9af3SAlexander Hansen if (ec.value() == EBADR) 1841599b9af3SAlexander Hansen { 1842599b9af3SAlexander Hansen messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 1843599b9af3SAlexander Hansen return; 1844599b9af3SAlexander Hansen } 1845599b9af3SAlexander Hansen // TODO Handle for specific error code 1846599b9af3SAlexander Hansen BMCWEB_LOG_ERROR( 1847599b9af3SAlexander Hansen "EventLogEntry (DBus) doDelete respHandler got error {}", ec); 1848599b9af3SAlexander Hansen asyncResp->res.result( 1849599b9af3SAlexander Hansen boost::beast::http::status::internal_server_error); 1850599b9af3SAlexander Hansen return; 1851599b9af3SAlexander Hansen } 1852599b9af3SAlexander Hansen 1853599b9af3SAlexander Hansen asyncResp->res.result(boost::beast::http::status::ok); 1854599b9af3SAlexander Hansen }; 1855599b9af3SAlexander Hansen 1856599b9af3SAlexander Hansen // Make call to Logging service to request Delete Log 1857599b9af3SAlexander Hansen crow::connections::systemBus->async_method_call( 1858599b9af3SAlexander Hansen respHandler, "xyz.openbmc_project.Logging", 1859599b9af3SAlexander Hansen "/xyz/openbmc_project/logging/entry/" + entryID, 1860599b9af3SAlexander Hansen "xyz.openbmc_project.Object.Delete", "Delete"); 18617e860f15SJohn Edward Broadbent } 18627e860f15SJohn Edward Broadbent 18637e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 18647e860f15SJohn Edward Broadbent { 18657e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 186622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1867ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1868002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1869002d39b4SEd Tanous [&app](const crow::Request& req, 18707e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1871898f2aa2SEd Tanous const std::string& systemName, const std::string& entryId) { 18723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 18737e860f15SJohn Edward Broadbent { 187445ca1b86SEd Tanous return; 187545ca1b86SEd Tanous } 187625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 18777f3e84a1SEd Tanous { 18787f3e84a1SEd Tanous // Option currently returns no systems. TBD 18797f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 18807f3e84a1SEd Tanous systemName); 18817f3e84a1SEd Tanous return; 18827f3e84a1SEd Tanous } 1883253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 188422d268cbSEd Tanous { 188522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 188622d268cbSEd Tanous systemName); 188722d268cbSEd Tanous return; 188822d268cbSEd Tanous } 188922d268cbSEd Tanous 1890898f2aa2SEd Tanous dBusEventLogEntryGet(asyncResp, entryId); 18917e860f15SJohn Edward Broadbent }); 1892336e96c6SChicago Duan 18937e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 189422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1895ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18967e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 189745ca1b86SEd Tanous [&app](const crow::Request& req, 18987e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 189922d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 19003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 190145ca1b86SEd Tanous { 190245ca1b86SEd Tanous return; 190345ca1b86SEd Tanous } 190425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19057f3e84a1SEd Tanous { 19067f3e84a1SEd Tanous // Option currently returns no systems. TBD 19077f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19087f3e84a1SEd Tanous systemName); 19097f3e84a1SEd Tanous return; 19107f3e84a1SEd Tanous } 1911253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 191222d268cbSEd Tanous { 191322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 191422d268cbSEd Tanous systemName); 191522d268cbSEd Tanous return; 191622d268cbSEd Tanous } 191775710de2SXiaochao Ma 1918599b9af3SAlexander Hansen dBusEventLogEntryPatch(req, asyncResp, entryId); 19197e860f15SJohn Edward Broadbent }); 192075710de2SXiaochao Ma 19217e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 192222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1923ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1924ed398213SEd Tanous 1925002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1926002d39b4SEd Tanous [&app](const crow::Request& req, 1927002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 192822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19293ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1930336e96c6SChicago Duan { 193145ca1b86SEd Tanous return; 193245ca1b86SEd Tanous } 193325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19347f3e84a1SEd Tanous { 19357f3e84a1SEd Tanous // Option currently returns no systems. TBD 19367f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19377f3e84a1SEd Tanous systemName); 19387f3e84a1SEd Tanous return; 19397f3e84a1SEd Tanous } 1940253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 194122d268cbSEd Tanous { 194222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 194322d268cbSEd Tanous systemName); 194422d268cbSEd Tanous return; 194522d268cbSEd Tanous } 1946599b9af3SAlexander Hansen dBusEventLogEntryDelete(asyncResp, param); 19477e860f15SJohn Edward Broadbent }); 1948400fd1fbSAdriana Kobylak } 1949400fd1fbSAdriana Kobylak 1950b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 1951b7028ebfSSpencer Ku 1952b7028ebfSSpencer Ku inline bool 1953b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 1954b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 1955b7028ebfSSpencer Ku { 1956b7028ebfSSpencer Ku std::error_code ec; 1957b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 1958b7028ebfSSpencer Ku if (ec) 1959b7028ebfSSpencer Ku { 1960bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 1961b7028ebfSSpencer Ku return false; 1962b7028ebfSSpencer Ku } 1963b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 1964b7028ebfSSpencer Ku { 1965b7028ebfSSpencer Ku std::string filename = it.path().filename(); 1966b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 1967b7028ebfSSpencer Ku // path 196811ba3979SEd Tanous if (filename.starts_with("log")) 1969b7028ebfSSpencer Ku { 1970b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 1971b7028ebfSSpencer Ku } 1972b7028ebfSSpencer Ku } 1973b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 1974b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 1975b7028ebfSSpencer Ku // descending order. 1976b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 1977b7028ebfSSpencer Ku AlphanumLess<std::string>()); 1978b7028ebfSSpencer Ku 1979b7028ebfSSpencer Ku return true; 1980b7028ebfSSpencer Ku } 1981b7028ebfSSpencer Ku 198202cad96eSEd Tanous inline bool getHostLoggerEntries( 198302cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 198402cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 1985b7028ebfSSpencer Ku { 1986b7028ebfSSpencer Ku GzFileReader logFile; 1987b7028ebfSSpencer Ku 1988b7028ebfSSpencer Ku // Go though all log files and expose host logs. 1989b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 1990b7028ebfSSpencer Ku { 1991b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 1992b7028ebfSSpencer Ku { 199362598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 1994b7028ebfSSpencer Ku return false; 1995b7028ebfSSpencer Ku } 1996b7028ebfSSpencer Ku } 1997b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 1998b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 1999b7028ebfSSpencer Ku if (!lastMessage.empty()) 2000b7028ebfSSpencer Ku { 2001b7028ebfSSpencer Ku logCount++; 2002b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2003b7028ebfSSpencer Ku { 2004b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2005b7028ebfSSpencer Ku } 2006b7028ebfSSpencer Ku } 2007b7028ebfSSpencer Ku return true; 2008b7028ebfSSpencer Ku } 2009b7028ebfSSpencer Ku 20106f056f24SEd Tanous inline void fillHostLoggerEntryJson(std::string_view logEntryID, 20116f056f24SEd Tanous std::string_view msg, 20126d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2013b7028ebfSSpencer Ku { 2014b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20159c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2016ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2017253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}", 2018253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 20196d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20206d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20216d6574c9SJason M. Bills logEntryJson["Message"] = msg; 2022539d8c6bSEd Tanous logEntryJson["EntryType"] = log_entry::LogEntryType::Oem; 2023539d8c6bSEd Tanous logEntryJson["Severity"] = log_entry::EventSeverity::OK; 20246d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2025b7028ebfSSpencer Ku } 2026b7028ebfSSpencer Ku 2027b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2028b7028ebfSSpencer Ku { 202922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2030b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20311476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20321476687dSEd Tanous [&app](const crow::Request& req, 203322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 203422d268cbSEd Tanous const std::string& systemName) { 20353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 203645ca1b86SEd Tanous { 203745ca1b86SEd Tanous return; 203845ca1b86SEd Tanous } 203925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20407f3e84a1SEd Tanous { 20417f3e84a1SEd Tanous // Option currently returns no systems. TBD 20427f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20437f3e84a1SEd Tanous systemName); 20447f3e84a1SEd Tanous return; 20457f3e84a1SEd Tanous } 2046253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 204722d268cbSEd Tanous { 204822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 204922d268cbSEd Tanous systemName); 205022d268cbSEd Tanous return; 205122d268cbSEd Tanous } 2052b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2053253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 2054253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2055b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2056b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2057b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2058b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2059b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 2060*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format( 2061*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2062253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2063b7028ebfSSpencer Ku }); 2064b7028ebfSSpencer Ku } 2065b7028ebfSSpencer Ku 2066b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2067b7028ebfSSpencer Ku { 2068b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 206922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2070b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2071*bd79bce8SPatrick Williams .methods( 2072*bd79bce8SPatrick Williams boost::beast::http::verb:: 2073*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 207422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 207522d268cbSEd Tanous const std::string& systemName) { 2076c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2077c937d2bfSEd Tanous .canDelegateTop = true, 2078c937d2bfSEd Tanous .canDelegateSkip = true, 2079c937d2bfSEd Tanous }; 2080c937d2bfSEd Tanous query_param::Query delegatedQuery; 2081c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 20823ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2083b7028ebfSSpencer Ku { 2084b7028ebfSSpencer Ku return; 2085b7028ebfSSpencer Ku } 208625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20877f3e84a1SEd Tanous { 20887f3e84a1SEd Tanous // Option currently returns no systems. TBD 20897f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20907f3e84a1SEd Tanous systemName); 20917f3e84a1SEd Tanous return; 20927f3e84a1SEd Tanous } 2093253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 209422d268cbSEd Tanous { 209522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 209622d268cbSEd Tanous systemName); 209722d268cbSEd Tanous return; 209822d268cbSEd Tanous } 2099*bd79bce8SPatrick Williams asyncResp->res.jsonValue["@odata.id"] = std::format( 2100*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2101253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2102b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2103b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2104b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2105b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2106b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21070fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2108b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2109b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2110b7028ebfSSpencer Ku 2111b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2112b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2113b7028ebfSSpencer Ku { 2114bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2115b7028ebfSSpencer Ku return; 2116b7028ebfSSpencer Ku } 21173648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21183648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 2119*bd79bce8SPatrick Williams size_t top = 2120*bd79bce8SPatrick Williams delegatedQuery.top.value_or(query_param::Query::maxTop); 2121b7028ebfSSpencer Ku size_t logCount = 0; 2122b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2123b7028ebfSSpencer Ku // control by skip and top. 2124b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21253648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21263648c8beSEd Tanous logCount)) 2127b7028ebfSSpencer Ku { 2128b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2129b7028ebfSSpencer Ku return; 2130b7028ebfSSpencer Ku } 2131b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2132b7028ebfSSpencer Ku // log count 213326f6976fSEd Tanous if (logEntries.empty()) 2134b7028ebfSSpencer Ku { 2135b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2136b7028ebfSSpencer Ku return; 2137b7028ebfSSpencer Ku } 213826f6976fSEd Tanous if (!logEntries.empty()) 2139b7028ebfSSpencer Ku { 2140b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2141b7028ebfSSpencer Ku { 21426d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 2143*bd79bce8SPatrick Williams fillHostLoggerEntryJson(std::to_string(skip + i), 2144*bd79bce8SPatrick Williams logEntries[i], hostLogEntry); 2145b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2146b7028ebfSSpencer Ku } 2147b7028ebfSSpencer Ku 2148b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21493648c8beSEd Tanous if (skip + top < logCount) 2150b7028ebfSSpencer Ku { 2151b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 2152253f11b8SEd Tanous std::format( 2153253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=", 2154253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 21553648c8beSEd Tanous std::to_string(skip + top); 2156b7028ebfSSpencer Ku } 2157b7028ebfSSpencer Ku } 2158b7028ebfSSpencer Ku }); 2159b7028ebfSSpencer Ku } 2160b7028ebfSSpencer Ku 2161b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2162b7028ebfSSpencer Ku { 2163b7028ebfSSpencer Ku BMCWEB_ROUTE( 216422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2165b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2166b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 216745ca1b86SEd Tanous [&app](const crow::Request& req, 2168b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 216922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21703ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 217145ca1b86SEd Tanous { 217245ca1b86SEd Tanous return; 217345ca1b86SEd Tanous } 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 } 21876f056f24SEd Tanous std::string_view targetID = param; 2188b7028ebfSSpencer Ku 2189b7028ebfSSpencer Ku uint64_t idInt = 0; 2190ca45aa3cSEd Tanous 2191*bd79bce8SPatrick Williams auto [ptr, ec] = 2192*bd79bce8SPatrick Williams std::from_chars(targetID.begin(), targetID.end(), idInt); 21936f056f24SEd Tanous if (ec != std::errc{} || ptr != targetID.end()) 2194b7028ebfSSpencer Ku { 2195*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "LogEntry", 2196*bd79bce8SPatrick Williams param); 2197b7028ebfSSpencer Ku return; 2198b7028ebfSSpencer Ku } 2199b7028ebfSSpencer Ku 2200b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2201b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2202b7028ebfSSpencer Ku { 2203bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2204b7028ebfSSpencer Ku return; 2205b7028ebfSSpencer Ku } 2206b7028ebfSSpencer Ku 2207b7028ebfSSpencer Ku size_t logCount = 0; 22083648c8beSEd Tanous size_t top = 1; 2209b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2210b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2211b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2212b7028ebfSSpencer Ku // get that entry 2213*bd79bce8SPatrick Williams if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, 2214*bd79bce8SPatrick Williams logEntries, logCount)) 2215b7028ebfSSpencer Ku { 2216b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2217b7028ebfSSpencer Ku return; 2218b7028ebfSSpencer Ku } 2219b7028ebfSSpencer Ku 2220b7028ebfSSpencer Ku if (!logEntries.empty()) 2221b7028ebfSSpencer Ku { 22226d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 2223*bd79bce8SPatrick Williams fillHostLoggerEntryJson(targetID, logEntries[0], 2224*bd79bce8SPatrick Williams hostLogEntry); 22256d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2226b7028ebfSSpencer Ku return; 2227b7028ebfSSpencer Ku } 2228b7028ebfSSpencer Ku 2229b7028ebfSSpencer Ku // Requested ID was not found 22309db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2231b7028ebfSSpencer Ku }); 2232b7028ebfSSpencer Ku } 2233b7028ebfSSpencer Ku 2234dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2235fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2236253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2237253f11b8SEd Tanous const std::string& managerId) 22381da66f75SEd Tanous { 22393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 224045ca1b86SEd Tanous { 224145ca1b86SEd Tanous return; 224245ca1b86SEd Tanous } 2243253f11b8SEd Tanous 2244253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2245253f11b8SEd Tanous { 2246253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2247253f11b8SEd Tanous return; 2248253f11b8SEd Tanous } 2249253f11b8SEd Tanous 22507e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22517e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2252e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22531da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2254253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2255253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME); 2256002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2257e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22581da66f75SEd Tanous "Collection of LogServices for this Manager"; 2259002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2260c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2261fdd26906SClaire Weinan 226225b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_BMC_JOURNAL) 226325b54dbaSEd Tanous { 2264613dabeaSEd Tanous nlohmann::json::object_t journal; 2265253f11b8SEd Tanous journal["@odata.id"] = 2266253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal", 2267253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2268b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 226925b54dbaSEd Tanous } 2270fdd26906SClaire Weinan 2271fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2272fdd26906SClaire Weinan 227325b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 227425b54dbaSEd Tanous { 227515912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 22767a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 22777a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 22787a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 227925b54dbaSEd Tanous [asyncResp](const boost::system::error_code& ec, 228025b54dbaSEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 228125b54dbaSEd Tanous subTreePaths) { 2282fdd26906SClaire Weinan if (ec) 2283fdd26906SClaire Weinan { 228462598e31SEd Tanous BMCWEB_LOG_ERROR( 228562598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 228662598e31SEd Tanous ec); 2287*bd79bce8SPatrick Williams // Assume that getting an error simply means there are no 2288*bd79bce8SPatrick Williams // dump LogServices. Return without adding any error 2289*bd79bce8SPatrick Williams // response. 2290fdd26906SClaire Weinan return; 2291fdd26906SClaire Weinan } 2292fdd26906SClaire Weinan 2293fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2294fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2295fdd26906SClaire Weinan 2296fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2297fdd26906SClaire Weinan { 2298fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2299fdd26906SClaire Weinan { 2300613dabeaSEd Tanous nlohmann::json::object_t member; 2301253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2302253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump", 2303253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2304b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2305fdd26906SClaire Weinan } 2306fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2307fdd26906SClaire Weinan { 2308613dabeaSEd Tanous nlohmann::json::object_t member; 2309253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2310253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/FaultLog", 2311253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2312b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2313fdd26906SClaire Weinan } 2314fdd26906SClaire Weinan } 2315fdd26906SClaire Weinan 2316e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2317fdd26906SClaire Weinan logServiceArrayLocal.size(); 23187a1dbc48SGeorge Liu }); 231925b54dbaSEd Tanous } 2320fdd26906SClaire Weinan } 2321fdd26906SClaire Weinan 2322fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2323fdd26906SClaire Weinan { 2324253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/") 2325fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2326fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2327dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2328e1f26343SJason M. Bills } 2329e1f26343SJason M. Bills 2330fdd26906SClaire Weinan inline void 2331fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2332fdd26906SClaire Weinan const std::string& dumpType) 2333c9bb6861Sraviteja-b { 2334fdd26906SClaire Weinan std::string dumpPath; 2335539d8c6bSEd Tanous log_service::OverWritePolicy overWritePolicy = 2336539d8c6bSEd Tanous log_service::OverWritePolicy::Invalid; 2337fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2338fdd26906SClaire Weinan 2339fdd26906SClaire Weinan if (dumpType == "BMC") 234045ca1b86SEd Tanous { 2341253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump", 2342253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2343539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::WrapsWhenFull; 2344fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2345fdd26906SClaire Weinan } 2346fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2347fdd26906SClaire Weinan { 2348253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog", 2349253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2350539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::Unknown; 2351fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2352fdd26906SClaire Weinan } 2353fdd26906SClaire Weinan else if (dumpType == "System") 2354fdd26906SClaire Weinan { 2355253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump", 2356253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2357539d8c6bSEd Tanous overWritePolicy = log_service::OverWritePolicy::WrapsWhenFull; 2358fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2359fdd26906SClaire Weinan } 2360fdd26906SClaire Weinan else 2361fdd26906SClaire Weinan { 236262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 236362598e31SEd Tanous dumpType); 2364fdd26906SClaire Weinan messages::internalError(asyncResp->res); 236545ca1b86SEd Tanous return; 236645ca1b86SEd Tanous } 2367fdd26906SClaire Weinan 2368fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2369fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2370c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2371fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2372fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2373539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = overWritePolicy; 23747c8c4058STejas Patil 23757c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23762b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 23770fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23787c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23797c8c4058STejas Patil redfishDateTimeOffset.second; 23807c8c4058STejas Patil 2381fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2382fdd26906SClaire Weinan 2383fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2384fdd26906SClaire Weinan { 2385002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 23861476687dSEd Tanous ["target"] = 2387fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2388fdd26906SClaire Weinan } 23890d946211SClaire Weinan 23900d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 23910d946211SClaire Weinan dbus::utility::getSubTreePaths( 23920d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 23930d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 23940d946211SClaire Weinan const boost::system::error_code& ec, 23950d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 23960d946211SClaire Weinan if (ec) 23970d946211SClaire Weinan { 2398*bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", 2399*bd79bce8SPatrick Williams ec); 24000d946211SClaire Weinan // Assume that getting an error simply means there are no dump 24010d946211SClaire Weinan // LogServices. Return without adding any error response. 24020d946211SClaire Weinan return; 24030d946211SClaire Weinan } 240418f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 24050d946211SClaire Weinan for (const std::string& path : subTreePaths) 24060d946211SClaire Weinan { 24070d946211SClaire Weinan if (path == dbusDumpPath) 24080d946211SClaire Weinan { 2409*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 2410*bd79bce8SPatrick Williams ["target"] = 24110d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 24120d946211SClaire Weinan break; 24130d946211SClaire Weinan } 24140d946211SClaire Weinan } 24150d946211SClaire Weinan }); 2416c9bb6861Sraviteja-b } 2417c9bb6861Sraviteja-b 2418fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2419fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2420253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2421253f11b8SEd Tanous const std::string& managerId) 24227e860f15SJohn Edward Broadbent { 24233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 242445ca1b86SEd Tanous { 242545ca1b86SEd Tanous return; 242645ca1b86SEd Tanous } 2427253f11b8SEd Tanous 2428253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2429253f11b8SEd Tanous { 2430253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2431253f11b8SEd Tanous return; 2432253f11b8SEd Tanous } 2433253f11b8SEd Tanous 2434fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2435fdd26906SClaire Weinan } 2436c9bb6861Sraviteja-b 243722d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 243822d268cbSEd Tanous crow::App& app, const crow::Request& req, 243922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 244022d268cbSEd Tanous const std::string& chassisId) 244122d268cbSEd Tanous { 244222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 244322d268cbSEd Tanous { 244422d268cbSEd Tanous return; 244522d268cbSEd Tanous } 2446253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 244722d268cbSEd Tanous { 244822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 244922d268cbSEd Tanous return; 245022d268cbSEd Tanous } 245122d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 245222d268cbSEd Tanous } 245322d268cbSEd Tanous 2454fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2455fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2456253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2457253f11b8SEd Tanous const std::string& managerId) 2458fdd26906SClaire Weinan { 2459fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2460fdd26906SClaire Weinan { 2461fdd26906SClaire Weinan return; 2462fdd26906SClaire Weinan } 2463253f11b8SEd Tanous 2464253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2465253f11b8SEd Tanous { 2466253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2467253f11b8SEd Tanous return; 2468253f11b8SEd Tanous } 2469fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2470fdd26906SClaire Weinan } 2471fdd26906SClaire Weinan 247222d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 247322d268cbSEd Tanous crow::App& app, const crow::Request& req, 247422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 247522d268cbSEd Tanous const std::string& chassisId) 247622d268cbSEd Tanous { 247722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 247822d268cbSEd Tanous { 247922d268cbSEd Tanous return; 248022d268cbSEd Tanous } 2481253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 248222d268cbSEd Tanous { 248322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 248422d268cbSEd Tanous return; 248522d268cbSEd Tanous } 248622d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 248722d268cbSEd Tanous } 248822d268cbSEd Tanous 2489fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2490fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2491fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2492253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2493fdd26906SClaire Weinan { 2494fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2495fdd26906SClaire Weinan { 2496fdd26906SClaire Weinan return; 2497fdd26906SClaire Weinan } 2498253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2499253f11b8SEd Tanous { 2500253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2501253f11b8SEd Tanous return; 2502253f11b8SEd Tanous } 2503fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2504fdd26906SClaire Weinan } 2505168d1b1aSCarson Labrado 250622d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 250722d268cbSEd Tanous crow::App& app, const crow::Request& req, 250822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 250922d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 251022d268cbSEd Tanous { 251122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 251222d268cbSEd Tanous { 251322d268cbSEd Tanous return; 251422d268cbSEd Tanous } 2515253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 251622d268cbSEd Tanous { 251722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 251822d268cbSEd Tanous return; 251922d268cbSEd Tanous } 252022d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 252122d268cbSEd Tanous } 2522fdd26906SClaire Weinan 2523fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2524fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2525fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2526253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2527fdd26906SClaire Weinan { 2528fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2529fdd26906SClaire Weinan { 2530fdd26906SClaire Weinan return; 2531fdd26906SClaire Weinan } 2532253f11b8SEd Tanous 2533253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2534253f11b8SEd Tanous { 2535253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2536253f11b8SEd Tanous return; 2537253f11b8SEd Tanous } 2538fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2539fdd26906SClaire Weinan } 2540fdd26906SClaire Weinan 254122d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 254222d268cbSEd Tanous crow::App& app, const crow::Request& req, 254322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 254422d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 254522d268cbSEd Tanous { 254622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 254722d268cbSEd Tanous { 254822d268cbSEd Tanous return; 254922d268cbSEd Tanous } 2550253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 255122d268cbSEd Tanous { 255222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 255322d268cbSEd Tanous return; 255422d268cbSEd Tanous } 255522d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 255622d268cbSEd Tanous } 255722d268cbSEd Tanous 2558168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2559168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2560168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2561253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2562168d1b1aSCarson Labrado { 2563168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2564168d1b1aSCarson Labrado { 2565168d1b1aSCarson Labrado return; 2566168d1b1aSCarson Labrado } 2567253f11b8SEd Tanous 2568253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2569253f11b8SEd Tanous { 2570253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2571253f11b8SEd Tanous return; 2572253f11b8SEd Tanous } 2573168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2574168d1b1aSCarson Labrado } 2575168d1b1aSCarson Labrado 2576168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2577168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2578168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2579168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2580168d1b1aSCarson Labrado { 2581168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2582168d1b1aSCarson Labrado { 2583168d1b1aSCarson Labrado return; 2584168d1b1aSCarson Labrado } 2585168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2586168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2587168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2588168d1b1aSCarson Labrado { 2589168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2590168d1b1aSCarson Labrado return; 2591168d1b1aSCarson Labrado } 2592168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2593168d1b1aSCarson Labrado } 2594168d1b1aSCarson Labrado 2595fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2596fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2597253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2598253f11b8SEd Tanous const std::string& managerId) 2599fdd26906SClaire Weinan { 2600fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2601fdd26906SClaire Weinan { 2602fdd26906SClaire Weinan return; 2603fdd26906SClaire Weinan } 2604253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2605253f11b8SEd Tanous { 2606253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2607253f11b8SEd Tanous return; 2608253f11b8SEd Tanous } 2609253f11b8SEd Tanous 2610fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2611fdd26906SClaire Weinan } 2612fdd26906SClaire Weinan 261322d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 261422d268cbSEd Tanous crow::App& app, const crow::Request& req, 261522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26167f3e84a1SEd Tanous const std::string& systemName) 261722d268cbSEd Tanous { 261822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 261922d268cbSEd Tanous { 262022d268cbSEd Tanous return; 262122d268cbSEd Tanous } 26227f3e84a1SEd Tanous 262325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 262422d268cbSEd Tanous { 26257f3e84a1SEd Tanous // Option currently returns no systems. TBD 26267f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26277f3e84a1SEd Tanous systemName); 26287f3e84a1SEd Tanous return; 26297f3e84a1SEd Tanous } 2630253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 26317f3e84a1SEd Tanous { 26327f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26337f3e84a1SEd Tanous systemName); 263422d268cbSEd Tanous return; 263522d268cbSEd Tanous } 263622d268cbSEd Tanous createDump(asyncResp, req, "System"); 263722d268cbSEd Tanous } 263822d268cbSEd Tanous 2639fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2640fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2641253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2642253f11b8SEd Tanous const std::string& managerId) 2643fdd26906SClaire Weinan { 2644fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2645fdd26906SClaire Weinan { 2646fdd26906SClaire Weinan return; 2647fdd26906SClaire Weinan } 2648253f11b8SEd Tanous 2649253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2650253f11b8SEd Tanous { 2651253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2652253f11b8SEd Tanous return; 2653253f11b8SEd Tanous } 2654fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2655fdd26906SClaire Weinan } 2656fdd26906SClaire Weinan 265722d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 265822d268cbSEd Tanous crow::App& app, const crow::Request& req, 265922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26607f3e84a1SEd Tanous const std::string& systemName) 266122d268cbSEd Tanous { 266222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 266322d268cbSEd Tanous { 266422d268cbSEd Tanous return; 266522d268cbSEd Tanous } 266625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 266722d268cbSEd Tanous { 26687f3e84a1SEd Tanous // Option currently returns no systems. TBD 26697f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26707f3e84a1SEd Tanous systemName); 26717f3e84a1SEd Tanous return; 26727f3e84a1SEd Tanous } 2673253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 26747f3e84a1SEd Tanous { 26757f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 26767f3e84a1SEd Tanous systemName); 267722d268cbSEd Tanous return; 267822d268cbSEd Tanous } 267922d268cbSEd Tanous clearDump(asyncResp, "System"); 268022d268cbSEd Tanous } 268122d268cbSEd Tanous 2682fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2683fdd26906SClaire Weinan { 2684253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/") 2685fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2686fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2687fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2688fdd26906SClaire Weinan } 2689fdd26906SClaire Weinan 2690fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2691fdd26906SClaire Weinan { 2692253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/") 2693fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2694fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2695fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2696c9bb6861Sraviteja-b } 2697c9bb6861Sraviteja-b 26987e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2699c9bb6861Sraviteja-b { 27007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2701253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2702ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2703fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2704fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2705fdd26906SClaire Weinan 27067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2707253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 2708ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2709fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2710fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2711c9bb6861Sraviteja-b } 2712c9bb6861Sraviteja-b 2713168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 2714168d1b1aSCarson Labrado { 2715168d1b1aSCarson Labrado BMCWEB_ROUTE( 2716168d1b1aSCarson Labrado app, 2717253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/") 2718168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2719168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2720168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 2721168d1b1aSCarson Labrado } 2722168d1b1aSCarson Labrado 27237e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2724c9bb6861Sraviteja-b { 27250fda0f12SGeorge Liu BMCWEB_ROUTE( 27260fda0f12SGeorge Liu app, 2727253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2728ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 27297e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2730fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2731fdd26906SClaire Weinan std::ref(app), "BMC")); 2732a43be80fSAsmitha Karunanithi } 2733a43be80fSAsmitha Karunanithi 27347e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 273580319af1SAsmitha Karunanithi { 27360fda0f12SGeorge Liu BMCWEB_ROUTE( 27370fda0f12SGeorge Liu app, 2738253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2739ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2740fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2741fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 274245ca1b86SEd Tanous } 2743fdd26906SClaire Weinan 2744168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 2745168d1b1aSCarson Labrado { 2746168d1b1aSCarson Labrado BMCWEB_ROUTE( 2747168d1b1aSCarson Labrado app, 27489e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 2749168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 2750168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 2751168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 2752168d1b1aSCarson Labrado } 2753168d1b1aSCarson Labrado 2754fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2755fdd26906SClaire Weinan { 2756253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/") 2757fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2758fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2759fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2760fdd26906SClaire Weinan } 2761fdd26906SClaire Weinan 2762fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2763fdd26906SClaire Weinan { 2764253f11b8SEd Tanous BMCWEB_ROUTE(app, 2765253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/") 2766fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2767fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2768fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2769fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2770fdd26906SClaire Weinan } 2771fdd26906SClaire Weinan 2772fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2773fdd26906SClaire Weinan { 2774253f11b8SEd Tanous BMCWEB_ROUTE( 2775253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2776fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2777fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2778fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2779fdd26906SClaire Weinan 2780253f11b8SEd Tanous BMCWEB_ROUTE( 2781253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 2782fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2783fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2784fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2785fdd26906SClaire Weinan } 2786fdd26906SClaire Weinan 2787fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2788fdd26906SClaire Weinan { 2789fdd26906SClaire Weinan BMCWEB_ROUTE( 2790fdd26906SClaire Weinan app, 2791253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/") 2792fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2793fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2794fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 27955cb1dd27SAsmitha Karunanithi } 27965cb1dd27SAsmitha Karunanithi 27977e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 27985cb1dd27SAsmitha Karunanithi { 279922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2800ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 28016ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 280222d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 28035cb1dd27SAsmitha Karunanithi } 28045cb1dd27SAsmitha Karunanithi 28057e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 28067e860f15SJohn Edward Broadbent { 280722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2808ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 280922d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 281022d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 281122d268cbSEd Tanous std::ref(app))); 28125cb1dd27SAsmitha Karunanithi } 28135cb1dd27SAsmitha Karunanithi 28147e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 28155cb1dd27SAsmitha Karunanithi { 28167e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 281722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2818ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 28196ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 282022d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 28218d1b46d7Szhanghch05 28227e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 282322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2824ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 28256ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 282622d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 28275cb1dd27SAsmitha Karunanithi } 2828c9bb6861Sraviteja-b 28297e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2830c9bb6861Sraviteja-b { 28310fda0f12SGeorge Liu BMCWEB_ROUTE( 28320fda0f12SGeorge Liu app, 283322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2834ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 283522d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 283622d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 283722d268cbSEd Tanous std::ref(app))); 2838a43be80fSAsmitha Karunanithi } 2839a43be80fSAsmitha Karunanithi 28407e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2841a43be80fSAsmitha Karunanithi { 28420fda0f12SGeorge Liu BMCWEB_ROUTE( 28430fda0f12SGeorge Liu app, 284422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2845ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28466ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 284722d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2848013487e5Sraviteja-b } 2849013487e5Sraviteja-b 28507e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 28511da66f75SEd Tanous { 28523946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 28533946028dSAppaRao Puli // method for security reasons. 28541da66f75SEd Tanous /** 28551da66f75SEd Tanous * Functions triggers appropriate requests on DBus 28561da66f75SEd Tanous */ 285722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2858ed398213SEd Tanous // This is incorrect, should be: 2859ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2860432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2861*bd79bce8SPatrick Williams .methods( 2862*bd79bce8SPatrick Williams boost::beast::http::verb:: 2863*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 286422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286522d268cbSEd Tanous const std::string& systemName) { 28663ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 286745ca1b86SEd Tanous { 286845ca1b86SEd Tanous return; 286945ca1b86SEd Tanous } 287025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 28717f3e84a1SEd Tanous { 28727f3e84a1SEd Tanous // Option currently returns no systems. TBD 28737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 28747f3e84a1SEd Tanous systemName); 28757f3e84a1SEd Tanous return; 28767f3e84a1SEd Tanous } 2877253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 287822d268cbSEd Tanous { 287922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 288022d268cbSEd Tanous systemName); 288122d268cbSEd Tanous return; 288222d268cbSEd Tanous } 288322d268cbSEd Tanous 28847e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 28857e860f15SJohn Edward Broadbent // SubRoute 28860f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2887253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 2888253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2889e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 28908e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 28914f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 28924f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 289315b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 2894539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 2895539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 2896e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 28977c8c4058STejas Patil 28987c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 28992b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 29007c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 29017c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 29027c8c4058STejas Patil redfishDateTimeOffset.second; 29037c8c4058STejas Patil 2904*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format( 2905*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 2906253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2907253f11b8SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 2908253f11b8SEd Tanous ["target"] = std::format( 2909253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog", 2910253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2911*bd79bce8SPatrick Williams asyncResp->res 2912*bd79bce8SPatrick Williams .jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 2913253f11b8SEd Tanous ["target"] = std::format( 2914253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData", 2915253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 29167e860f15SJohn Edward Broadbent }); 29171da66f75SEd Tanous } 29181da66f75SEd Tanous 29197e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 29205b61b5e8SJason M. Bills { 29210fda0f12SGeorge Liu BMCWEB_ROUTE( 29220fda0f12SGeorge Liu app, 292322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 2924ed398213SEd Tanous // This is incorrect, should be: 2925ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 2926432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 29277e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 292845ca1b86SEd Tanous [&app](const crow::Request& req, 292922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 293022d268cbSEd Tanous const std::string& systemName) { 29313ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 293245ca1b86SEd Tanous { 293345ca1b86SEd Tanous return; 293445ca1b86SEd Tanous } 293525b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 29367f3e84a1SEd Tanous { 29377f3e84a1SEd Tanous // Option currently returns no systems. TBD 29387f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29397f3e84a1SEd Tanous systemName); 29407f3e84a1SEd Tanous return; 29417f3e84a1SEd Tanous } 2942253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 294322d268cbSEd Tanous { 294422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 294522d268cbSEd Tanous systemName); 294622d268cbSEd Tanous return; 294722d268cbSEd Tanous } 29485b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 29495e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 2950cb13a392SEd Tanous const std::string&) { 29515b61b5e8SJason M. Bills if (ec) 29525b61b5e8SJason M. Bills { 29535b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 29545b61b5e8SJason M. Bills return; 29555b61b5e8SJason M. Bills } 29565b61b5e8SJason M. Bills messages::success(asyncResp->res); 29575b61b5e8SJason M. Bills }, 2958*bd79bce8SPatrick Williams crashdumpObject, crashdumpPath, deleteAllInterface, 2959*bd79bce8SPatrick Williams "DeleteAll"); 29607e860f15SJohn Edward Broadbent }); 29615b61b5e8SJason M. Bills } 29625b61b5e8SJason M. Bills 29638d1b46d7Szhanghch05 static void 29648d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29658d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 2966e855dd28SJason M. Bills { 2967043a0536SJohnathan Mantey auto getStoredLogCallback = 2968b9d36b47SEd Tanous [asyncResp, logID, 29695e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 2970b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 2971e855dd28SJason M. Bills if (ec) 2972e855dd28SJason M. Bills { 297362598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 29741ddcf01aSJason M. Bills if (ec.value() == 29751ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 29761ddcf01aSJason M. Bills { 2977*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "LogEntry", 2978*bd79bce8SPatrick Williams logID); 29791ddcf01aSJason M. Bills } 29801ddcf01aSJason M. Bills else 29811ddcf01aSJason M. Bills { 2982e855dd28SJason M. Bills messages::internalError(asyncResp->res); 29831ddcf01aSJason M. Bills } 2984e855dd28SJason M. Bills return; 2985e855dd28SJason M. Bills } 2986043a0536SJohnathan Mantey 2987043a0536SJohnathan Mantey std::string timestamp{}; 2988043a0536SJohnathan Mantey std::string filename{}; 2989043a0536SJohnathan Mantey std::string logfile{}; 29902c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 2991043a0536SJohnathan Mantey 2992043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 2993e855dd28SJason M. Bills { 29949db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 2995e855dd28SJason M. Bills return; 2996e855dd28SJason M. Bills } 2997e855dd28SJason M. Bills 2998043a0536SJohnathan Mantey std::string crashdumpURI = 2999*bd79bce8SPatrick Williams std::format( 3000*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/", 3001253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3002043a0536SJohnathan Mantey logID + "/" + filename; 300384afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30049c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3005ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3006253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}", 3007253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logID); 300884afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 300984afc48bSJason M. Bills logEntry["Id"] = logID; 3010539d8c6bSEd Tanous logEntry["EntryType"] = log_entry::LogEntryType::Oem; 301184afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 301284afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 301384afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 301484afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 30152b20ef6eSJason M. Bills 30162b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 30172b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 30182b20ef6eSJason M. Bills // directly 30192b20ef6eSJason M. Bills if (logEntryJson.is_array()) 30202b20ef6eSJason M. Bills { 30212b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 30222b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 30232b20ef6eSJason M. Bills logEntryJson.size(); 30242b20ef6eSJason M. Bills } 30252b20ef6eSJason M. Bills else 30262b20ef6eSJason M. Bills { 3027d405bb51SJason M. Bills logEntryJson.update(logEntry); 30282b20ef6eSJason M. Bills } 3029e855dd28SJason M. Bills }; 3030d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3031d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3032d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3033d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3034e855dd28SJason M. Bills } 3035e855dd28SJason M. Bills 30367e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 30371da66f75SEd Tanous { 30383946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30393946028dSAppaRao Puli // method for security reasons. 30401da66f75SEd Tanous /** 30411da66f75SEd Tanous * Functions triggers appropriate requests on DBus 30421da66f75SEd Tanous */ 30437e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 304422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3045ed398213SEd Tanous // This is incorrect, should be. 3046ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3047432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3048*bd79bce8SPatrick Williams .methods( 3049*bd79bce8SPatrick Williams boost::beast::http::verb:: 3050*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 305122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 305222d268cbSEd Tanous const std::string& systemName) { 30533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 305445ca1b86SEd Tanous { 305545ca1b86SEd Tanous return; 305645ca1b86SEd Tanous } 305725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 30587f3e84a1SEd Tanous { 30597f3e84a1SEd Tanous // Option currently returns no systems. TBD 30607f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30617f3e84a1SEd Tanous systemName); 30627f3e84a1SEd Tanous return; 30637f3e84a1SEd Tanous } 3064253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 306522d268cbSEd Tanous { 306622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 306722d268cbSEd Tanous systemName); 306822d268cbSEd Tanous return; 306922d268cbSEd Tanous } 307022d268cbSEd Tanous 30717a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 30727a1dbc48SGeorge Liu crashdumpInterface}; 30737a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 30747a1dbc48SGeorge Liu "/", 0, interfaces, 30757a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 30762b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 30771da66f75SEd Tanous if (ec) 30781da66f75SEd Tanous { 30791da66f75SEd Tanous if (ec.value() != 30801da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 30811da66f75SEd Tanous { 308262598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 308362598e31SEd Tanous ec.message()); 3084f12894f8SJason M. Bills messages::internalError(asyncResp->res); 30851da66f75SEd Tanous return; 30861da66f75SEd Tanous } 30871da66f75SEd Tanous } 3088e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 30891da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 3090253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 3091253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 3092253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3093*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 3094*bd79bce8SPatrick Williams "Open BMC Crashdump Entries"; 3095e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3096424c4176SJason M. Bills "Collection of Crashdump Entries"; 3097*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"] = 3098*bd79bce8SPatrick Williams nlohmann::json::array(); 3099a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31002b20ef6eSJason M. Bills 31012b20ef6eSJason M. Bills for (const std::string& path : resp) 31021da66f75SEd Tanous { 31032b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3104e855dd28SJason M. Bills // Get the log ID 31052b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31062b20ef6eSJason M. Bills if (logID.empty()) 31071da66f75SEd Tanous { 3108e855dd28SJason M. Bills continue; 31091da66f75SEd Tanous } 3110e855dd28SJason M. Bills // Add the log entry to the array 31112b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31122b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31131da66f75SEd Tanous } 31147a1dbc48SGeorge Liu }); 31157e860f15SJohn Edward Broadbent }); 31161da66f75SEd Tanous } 31171da66f75SEd Tanous 31187e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31191da66f75SEd Tanous { 31203946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31213946028dSAppaRao Puli // method for security reasons. 31221da66f75SEd Tanous 31237e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 312422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3125ed398213SEd Tanous // this is incorrect, should be 3126ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3127432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 31287e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 312945ca1b86SEd Tanous [&app](const crow::Request& req, 31307e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 313122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 31323ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 313345ca1b86SEd Tanous { 313445ca1b86SEd Tanous return; 313545ca1b86SEd Tanous } 313625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 31377f3e84a1SEd Tanous { 31387f3e84a1SEd Tanous // Option currently returns no systems. TBD 31397f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31407f3e84a1SEd Tanous systemName); 31417f3e84a1SEd Tanous return; 31427f3e84a1SEd Tanous } 3143253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 314422d268cbSEd Tanous { 314522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 314622d268cbSEd Tanous systemName); 314722d268cbSEd Tanous return; 314822d268cbSEd Tanous } 31497e860f15SJohn Edward Broadbent const std::string& logID = param; 3150e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 31517e860f15SJohn Edward Broadbent }); 3152e855dd28SJason M. Bills } 3153e855dd28SJason M. Bills 31547e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3155e855dd28SJason M. Bills { 31563946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31573946028dSAppaRao Puli // method for security reasons. 31587e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 31597e860f15SJohn Edward Broadbent app, 316022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3161ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 31627e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3163a4ce114aSNan Zhou [](const crow::Request& req, 31647e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 316522d268cbSEd Tanous const std::string& systemName, const std::string& logID, 316622d268cbSEd Tanous const std::string& fileName) { 3167*bd79bce8SPatrick Williams // Do not call getRedfishRoute here since the crashdump file is 3168*bd79bce8SPatrick Williams // not a Redfish resource. 316922d268cbSEd Tanous 317025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 31717f3e84a1SEd Tanous { 31727f3e84a1SEd Tanous // Option currently returns no systems. TBD 31737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31747f3e84a1SEd Tanous systemName); 31757f3e84a1SEd Tanous return; 31767f3e84a1SEd Tanous } 3177253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 317822d268cbSEd Tanous { 317922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 318022d268cbSEd Tanous systemName); 318122d268cbSEd Tanous return; 318222d268cbSEd Tanous } 318322d268cbSEd Tanous 3184043a0536SJohnathan Mantey auto getStoredLogCallback = 3185*bd79bce8SPatrick Williams [asyncResp, logID, fileName, 3186*bd79bce8SPatrick Williams url(boost::urls::url(req.url()))]( 31875e7e2dc5SEd Tanous const boost::system::error_code& ec, 3188*bd79bce8SPatrick Williams const std::vector<std::pair< 3189*bd79bce8SPatrick Williams std::string, dbus::utility::DbusVariantType>>& 31907e860f15SJohn Edward Broadbent resp) { 31911da66f75SEd Tanous if (ec) 31921da66f75SEd Tanous { 3193*bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("failed to get log ec: {}", 3194*bd79bce8SPatrick Williams ec.message()); 3195f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31961da66f75SEd Tanous return; 31971da66f75SEd Tanous } 3198e855dd28SJason M. Bills 3199043a0536SJohnathan Mantey std::string dbusFilename{}; 3200043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3201043a0536SJohnathan Mantey std::string dbusFilepath{}; 3202043a0536SJohnathan Mantey 3203*bd79bce8SPatrick Williams parseCrashdumpParameters(resp, dbusFilename, 3204*bd79bce8SPatrick Williams dbusTimestamp, dbusFilepath); 3205043a0536SJohnathan Mantey 3206043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3207043a0536SJohnathan Mantey dbusFilepath.empty()) 32081da66f75SEd Tanous { 3209*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 3210*bd79bce8SPatrick Williams "LogEntry", logID); 32111da66f75SEd Tanous return; 32121da66f75SEd Tanous } 3213e855dd28SJason M. Bills 3214043a0536SJohnathan Mantey // Verify the file name parameter is correct 3215043a0536SJohnathan Mantey if (fileName != dbusFilename) 3216043a0536SJohnathan Mantey { 3217*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 3218*bd79bce8SPatrick Williams "LogEntry", logID); 3219043a0536SJohnathan Mantey return; 3220043a0536SJohnathan Mantey } 3221043a0536SJohnathan Mantey 322227b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3223043a0536SJohnathan Mantey { 3224*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 3225*bd79bce8SPatrick Williams "LogEntry", logID); 3226043a0536SJohnathan Mantey return; 3227043a0536SJohnathan Mantey } 3228043a0536SJohnathan Mantey 32297e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32307e860f15SJohn Edward Broadbent // from a browser 3231d9f6c621SEd Tanous asyncResp->res.addHeader( 3232*bd79bce8SPatrick Williams boost::beast::http::field::content_disposition, 3233*bd79bce8SPatrick Williams "attachment"); 32341da66f75SEd Tanous }; 3235d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3236d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3237*bd79bce8SPatrick Williams crashdumpPath + std::string("/") + logID, 3238*bd79bce8SPatrick Williams crashdumpInterface, std::move(getStoredLogCallback)); 32397e860f15SJohn Edward Broadbent }); 32401da66f75SEd Tanous } 32411da66f75SEd Tanous 3242c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3243c5a4c82aSJason M. Bills { 3244c5a4c82aSJason M. Bills onDemand, 3245c5a4c82aSJason M. Bills telemetry, 3246c5a4c82aSJason M. Bills invalid, 3247c5a4c82aSJason M. Bills }; 3248c5a4c82aSJason M. Bills 324926ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3250c5a4c82aSJason M. Bills { 3251c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3252c5a4c82aSJason M. Bills { 3253c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3254c5a4c82aSJason M. Bills } 3255c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3256c5a4c82aSJason M. Bills { 3257c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3258c5a4c82aSJason M. Bills } 3259c5a4c82aSJason M. Bills 3260c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3261c5a4c82aSJason M. Bills } 3262c5a4c82aSJason M. Bills 32637e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 32641da66f75SEd Tanous { 32653946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32663946028dSAppaRao Puli // method for security reasons. 32670fda0f12SGeorge Liu BMCWEB_ROUTE( 32680fda0f12SGeorge Liu app, 326922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3270ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3271ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3272432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3273002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3274002d39b4SEd Tanous [&app](const crow::Request& req, 327522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 327622d268cbSEd Tanous const std::string& systemName) { 32773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 327845ca1b86SEd Tanous { 327945ca1b86SEd Tanous return; 328045ca1b86SEd Tanous } 328122d268cbSEd Tanous 328225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 32837f3e84a1SEd Tanous { 32847f3e84a1SEd Tanous // Option currently returns no systems. TBD 32857f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32867f3e84a1SEd Tanous systemName); 32877f3e84a1SEd Tanous return; 32887f3e84a1SEd Tanous } 3289253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 329022d268cbSEd Tanous { 329122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 329222d268cbSEd Tanous systemName); 329322d268cbSEd Tanous return; 329422d268cbSEd Tanous } 329522d268cbSEd Tanous 32968e6c099aSJason M. Bills std::string diagnosticDataType; 32978e6c099aSJason M. Bills std::string oemDiagnosticDataType; 329815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3299*bd79bce8SPatrick Williams req, asyncResp->res, "DiagnosticDataType", 3300*bd79bce8SPatrick Williams diagnosticDataType, "OEMDiagnosticDataType", 3301*bd79bce8SPatrick Williams oemDiagnosticDataType)) 33028e6c099aSJason M. Bills { 33038e6c099aSJason M. Bills return; 33048e6c099aSJason M. Bills } 33058e6c099aSJason M. Bills 33068e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33078e6c099aSJason M. Bills { 330862598e31SEd Tanous BMCWEB_LOG_ERROR( 330962598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 33108e6c099aSJason M. Bills messages::actionParameterValueFormatError( 3311*bd79bce8SPatrick Williams asyncResp->res, diagnosticDataType, 3312*bd79bce8SPatrick Williams "DiagnosticDataType", "CollectDiagnosticData"); 33138e6c099aSJason M. Bills return; 33148e6c099aSJason M. Bills } 33158e6c099aSJason M. Bills 3316c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3317c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3318c5a4c82aSJason M. Bills 3319c5a4c82aSJason M. Bills std::string iface; 3320c5a4c82aSJason M. Bills std::string method; 3321c5a4c82aSJason M. Bills std::string taskMatchStr; 3322c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3323c5a4c82aSJason M. Bills { 3324c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3325c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3326*bd79bce8SPatrick Williams taskMatchStr = 3327*bd79bce8SPatrick Williams "type='signal'," 3328c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3329c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3330c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3331c5a4c82aSJason M. Bills } 3332c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3333c5a4c82aSJason M. Bills { 3334c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3335c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3336*bd79bce8SPatrick Williams taskMatchStr = 3337*bd79bce8SPatrick Williams "type='signal'," 3338c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3339c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3340c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3341c5a4c82aSJason M. Bills } 3342c5a4c82aSJason M. Bills else 3343c5a4c82aSJason M. Bills { 334462598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 334562598e31SEd Tanous oemDiagnosticDataType); 3346c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3347*bd79bce8SPatrick Williams asyncResp->res, oemDiagnosticDataType, 3348*bd79bce8SPatrick Williams "OEMDiagnosticDataType", "CollectDiagnosticData"); 3349c5a4c82aSJason M. Bills return; 3350c5a4c82aSJason M. Bills } 3351c5a4c82aSJason M. Bills 3352c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3353c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 33545e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 335598be3e39SEd Tanous const std::string&) mutable { 33561da66f75SEd Tanous if (ec) 33571da66f75SEd Tanous { 3358*bd79bce8SPatrick Williams if (ec.value() == 3359*bd79bce8SPatrick Williams boost::system::errc::operation_not_supported) 33601da66f75SEd Tanous { 3361f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 33621da66f75SEd Tanous } 3363*bd79bce8SPatrick Williams else if (ec.value() == boost::system::errc:: 3364*bd79bce8SPatrick Williams device_or_resource_busy) 33654363d3b2SJason M. Bills { 3366*bd79bce8SPatrick Williams messages::serviceTemporarilyUnavailable( 3367*bd79bce8SPatrick Williams asyncResp->res, "60"); 33684363d3b2SJason M. Bills } 33691da66f75SEd Tanous else 33701da66f75SEd Tanous { 3371f12894f8SJason M. Bills messages::internalError(asyncResp->res); 33721da66f75SEd Tanous } 33731da66f75SEd Tanous return; 33741da66f75SEd Tanous } 3375*bd79bce8SPatrick Williams std::shared_ptr<task::TaskData> task = 3376*bd79bce8SPatrick Williams task::TaskData::createTask( 3377*bd79bce8SPatrick Williams [](const boost::system::error_code& ec2, 3378*bd79bce8SPatrick Williams sdbusplus::message_t&, 3379*bd79bce8SPatrick Williams const std::shared_ptr<task::TaskData>& 3380*bd79bce8SPatrick Williams taskData) { 33818b24275dSEd Tanous if (!ec2) 338266afe4faSJames Feist { 3383*bd79bce8SPatrick Williams taskData->messages.emplace_back( 3384*bd79bce8SPatrick Williams messages::taskCompletedOK( 3385*bd79bce8SPatrick Williams std::to_string( 3386*bd79bce8SPatrick Williams taskData->index))); 3387831d6b09SJames Feist taskData->state = "Completed"; 338866afe4faSJames Feist } 338932898ceaSJames Feist return task::completed; 339066afe4faSJames Feist }, 3391c5a4c82aSJason M. Bills taskMatchStr); 3392c5a4c82aSJason M. Bills 339346229577SJames Feist task->startTimer(std::chrono::minutes(5)); 339446229577SJames Feist task->populateResp(asyncResp->res); 339598be3e39SEd Tanous task->payload.emplace(std::move(payload)); 33961da66f75SEd Tanous }; 33978e6c099aSJason M. Bills 33981da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3399*bd79bce8SPatrick Williams std::move(collectCrashdumpCallback), crashdumpObject, 3400*bd79bce8SPatrick Williams crashdumpPath, iface, method); 34017e860f15SJohn Edward Broadbent }); 34026eda7685SKenny L. Ku } 34036eda7685SKenny L. Ku 3404599b9af3SAlexander Hansen inline void dBusLogServiceActionsClear( 3405599b9af3SAlexander Hansen const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3406599b9af3SAlexander Hansen { 3407599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("Do delete all entries."); 3408599b9af3SAlexander Hansen 3409599b9af3SAlexander Hansen // Process response from Logging service. 3410599b9af3SAlexander Hansen auto respHandler = [asyncResp](const boost::system::error_code& ec) { 3411599b9af3SAlexander Hansen BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3412599b9af3SAlexander Hansen if (ec) 3413599b9af3SAlexander Hansen { 3414599b9af3SAlexander Hansen // TODO Handle for specific error code 3415599b9af3SAlexander Hansen BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3416599b9af3SAlexander Hansen asyncResp->res.result( 3417599b9af3SAlexander Hansen boost::beast::http::status::internal_server_error); 3418599b9af3SAlexander Hansen return; 3419599b9af3SAlexander Hansen } 3420599b9af3SAlexander Hansen 3421599b9af3SAlexander Hansen asyncResp->res.result(boost::beast::http::status::no_content); 3422599b9af3SAlexander Hansen }; 3423599b9af3SAlexander Hansen 3424599b9af3SAlexander Hansen // Make call to Logging service to request Clear Log 3425599b9af3SAlexander Hansen crow::connections::systemBus->async_method_call( 3426599b9af3SAlexander Hansen respHandler, "xyz.openbmc_project.Logging", 3427599b9af3SAlexander Hansen "/xyz/openbmc_project/logging", 3428599b9af3SAlexander Hansen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 3429599b9af3SAlexander Hansen } 3430599b9af3SAlexander Hansen 3431cb92c03bSAndrew Geissler /** 3432cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3433cb92c03bSAndrew Geissler */ 34347e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3435cb92c03bSAndrew Geissler { 3436cb92c03bSAndrew Geissler /** 3437cb92c03bSAndrew Geissler * Function handles POST method request. 3438cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3439cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3440cb92c03bSAndrew Geissler */ 34417e860f15SJohn Edward Broadbent 34420fda0f12SGeorge Liu BMCWEB_ROUTE( 34430fda0f12SGeorge Liu app, 344422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3445ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34467e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 344745ca1b86SEd Tanous [&app](const crow::Request& req, 344822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 344922d268cbSEd Tanous const std::string& systemName) { 34503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 345145ca1b86SEd Tanous { 345245ca1b86SEd Tanous return; 345345ca1b86SEd Tanous } 345425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 34557f3e84a1SEd Tanous { 34567f3e84a1SEd Tanous // Option currently returns no systems. TBD 34577f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34587f3e84a1SEd Tanous systemName); 34597f3e84a1SEd Tanous return; 34607f3e84a1SEd Tanous } 3461253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 346222d268cbSEd Tanous { 346322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 346422d268cbSEd Tanous systemName); 346522d268cbSEd Tanous return; 346622d268cbSEd Tanous } 3467599b9af3SAlexander Hansen dBusLogServiceActionsClear(asyncResp); 34687e860f15SJohn Edward Broadbent }); 3469cb92c03bSAndrew Geissler } 3470a3316fc6SZhikuiRen 3471a3316fc6SZhikuiRen /**************************************************** 3472a3316fc6SZhikuiRen * Redfish PostCode interfaces 3473a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3474a3316fc6SZhikuiRen ******************************************************/ 34757e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3476a3316fc6SZhikuiRen { 347722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3478ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3479*bd79bce8SPatrick Williams .methods( 3480*bd79bce8SPatrick Williams boost::beast::http::verb:: 3481*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 348222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 348322d268cbSEd Tanous const std::string& systemName) { 34843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 348545ca1b86SEd Tanous { 348645ca1b86SEd Tanous return; 348745ca1b86SEd Tanous } 348825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 34897f3e84a1SEd Tanous { 34907f3e84a1SEd Tanous // Option currently returns no systems. TBD 34917f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34927f3e84a1SEd Tanous systemName); 34937f3e84a1SEd Tanous return; 34947f3e84a1SEd Tanous } 3495253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 349622d268cbSEd Tanous { 349722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 349822d268cbSEd Tanous systemName); 349922d268cbSEd Tanous return; 350022d268cbSEd Tanous } 35011476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3502253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 3503253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35041476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3505b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 35061476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35071476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3508ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 3509539d8c6bSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = 3510539d8c6bSEd Tanous log_service::OverWritePolicy::WrapsWhenFull; 3511*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format( 3512*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3513253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35147c8c4058STejas Patil 35157c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35162b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35170fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35187c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35197c8c4058STejas Patil redfishDateTimeOffset.second; 35207c8c4058STejas Patil 352120fa6a2cSEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 352220fa6a2cSEd Tanous ["target"] = std::format( 3523253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 352420fa6a2cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 35257e860f15SJohn Edward Broadbent }); 3526a3316fc6SZhikuiRen } 3527a3316fc6SZhikuiRen 35287e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3529a3316fc6SZhikuiRen { 35300fda0f12SGeorge Liu BMCWEB_ROUTE( 35310fda0f12SGeorge Liu app, 353222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3533ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3534ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3535432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35367e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 353745ca1b86SEd Tanous [&app](const crow::Request& req, 353822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 353922d268cbSEd Tanous const std::string& systemName) { 35403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 354145ca1b86SEd Tanous { 354245ca1b86SEd Tanous return; 354345ca1b86SEd Tanous } 354425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35457f3e84a1SEd Tanous { 35467f3e84a1SEd Tanous // Option currently returns no systems. TBD 35477f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35487f3e84a1SEd Tanous systemName); 35497f3e84a1SEd Tanous return; 35507f3e84a1SEd Tanous } 3551253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 355222d268cbSEd Tanous { 355322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 355422d268cbSEd Tanous systemName); 355522d268cbSEd Tanous return; 355622d268cbSEd Tanous } 355762598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3558a3316fc6SZhikuiRen 3559a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3560a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 35615e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3562a3316fc6SZhikuiRen if (ec) 3563a3316fc6SZhikuiRen { 3564a3316fc6SZhikuiRen // TODO Handle for specific error code 3565*bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 3566*bd79bce8SPatrick Williams "doClearPostCodes resp_handler got error {}", 356762598e31SEd Tanous ec); 3568*bd79bce8SPatrick Williams asyncResp->res.result(boost::beast::http::status:: 3569*bd79bce8SPatrick Williams internal_server_error); 3570a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3571a3316fc6SZhikuiRen return; 3572a3316fc6SZhikuiRen } 357318fc70c0STony Lee messages::success(asyncResp->res); 3574a3316fc6SZhikuiRen }, 357515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 357615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3577a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35787e860f15SJohn Edward Broadbent }); 3579a3316fc6SZhikuiRen } 3580a3316fc6SZhikuiRen 35816f284d24SJiaqing Zhao /** 35826f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 35836f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 35846f284d24SJiaqing Zhao * 35856f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 35866f284d24SJiaqing Zhao * @param[out] currentValue Current value 35876f284d24SJiaqing Zhao * @param[out] index Index value 35886f284d24SJiaqing Zhao * 35896f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 35906f284d24SJiaqing Zhao */ 35916f056f24SEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 3592df254f2cSEd Tanous uint16_t& index) 35936f284d24SJiaqing Zhao { 35946f284d24SJiaqing Zhao std::vector<std::string> split; 359550ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 35966f056f24SEd Tanous if (split.size() != 2) 35976f056f24SEd Tanous { 35986f056f24SEd Tanous return false; 35996f056f24SEd Tanous } 36006f056f24SEd Tanous std::string_view postCodeNumber = split[0]; 36016f056f24SEd Tanous if (postCodeNumber.size() < 2) 36026f056f24SEd Tanous { 36036f056f24SEd Tanous return false; 36046f056f24SEd Tanous } 36056f056f24SEd Tanous if (postCodeNumber[0] != 'B') 36066f056f24SEd Tanous { 36076f056f24SEd Tanous return false; 36086f056f24SEd Tanous } 36096f056f24SEd Tanous postCodeNumber.remove_prefix(1); 3610*bd79bce8SPatrick Williams auto [ptrIndex, ecIndex] = 3611*bd79bce8SPatrick Williams std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index); 36126f056f24SEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 36136f284d24SJiaqing Zhao { 36146f284d24SJiaqing Zhao return false; 36156f284d24SJiaqing Zhao } 36166f284d24SJiaqing Zhao 36176f056f24SEd Tanous std::string_view postCodeIndex = split[1]; 36186f284d24SJiaqing Zhao 36196f056f24SEd Tanous auto [ptrValue, ecValue] = std::from_chars( 36206f056f24SEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 36216f284d24SJiaqing Zhao 36226f056f24SEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 36236f284d24SJiaqing Zhao } 36246f284d24SJiaqing Zhao 36256f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3626ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36276c9a279eSManojkiran Eda const boost::container::flat_map< 36286c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3629a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3630a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3631a3316fc6SZhikuiRen { 3632a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3633fffb8c1fSEd Tanous const registries::Message* message = 3634fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3635dc8cfa66SEd Tanous if (message == nullptr) 3636dc8cfa66SEd Tanous { 3637dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 3638dc8cfa66SEd Tanous return false; 3639dc8cfa66SEd Tanous } 3640a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3641a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 36426c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36436c9a279eSManojkiran Eda code : postcode) 3644a3316fc6SZhikuiRen { 3645a3316fc6SZhikuiRen currentCodeIndex++; 3646a3316fc6SZhikuiRen std::string postcodeEntryID = 3647a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3648a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3649a3316fc6SZhikuiRen 3650a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3651a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3652a3316fc6SZhikuiRen 3653a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3654a3316fc6SZhikuiRen { // already incremented 3655a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3656a3316fc6SZhikuiRen } 3657a3316fc6SZhikuiRen else 3658a3316fc6SZhikuiRen { 3659a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3660a3316fc6SZhikuiRen } 3661a3316fc6SZhikuiRen 3662a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3663a3316fc6SZhikuiRen // not fall between top and skip 3664a3316fc6SZhikuiRen if ((codeIndex == 0) && 3665a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3666a3316fc6SZhikuiRen { 3667a3316fc6SZhikuiRen continue; 3668a3316fc6SZhikuiRen } 3669a3316fc6SZhikuiRen 36704e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3671a3316fc6SZhikuiRen // currentIndex 3672a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3673a3316fc6SZhikuiRen { 3674a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3675a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3676a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3677a3316fc6SZhikuiRen continue; 3678a3316fc6SZhikuiRen } 3679a3316fc6SZhikuiRen 3680a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3681a3316fc6SZhikuiRen // index 3682a3316fc6SZhikuiRen 3683a3316fc6SZhikuiRen // Get the Created time from the timestamp 3684a3316fc6SZhikuiRen std::string entryTimeStr; 36852a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3686a3316fc6SZhikuiRen 3687a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3688a3316fc6SZhikuiRen std::ostringstream hexCode; 3689a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 36906c9a279eSManojkiran Eda << std::get<0>(code.second); 3691a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3692a3316fc6SZhikuiRen // Set Fixed -Point Notation 3693a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3694a3316fc6SZhikuiRen // Set precision to 4 digits 3695a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3696a3316fc6SZhikuiRen // Add double to stream 3697a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3698a3316fc6SZhikuiRen 36991e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 37001e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 37011e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3702a3316fc6SZhikuiRen 37031e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 37041e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 37051e6deaf6SEd Tanous 37061e6deaf6SEd Tanous std::string msg = 37071e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 37081e6deaf6SEd Tanous if (msg.empty()) 3709a3316fc6SZhikuiRen { 37101e6deaf6SEd Tanous messages::internalError(asyncResp->res); 37111e6deaf6SEd Tanous return false; 3712a3316fc6SZhikuiRen } 3713a3316fc6SZhikuiRen 3714d4342a92STim Lee // Get Severity template from message registry 3715d4342a92STim Lee std::string severity; 3716d4342a92STim Lee if (message != nullptr) 3717d4342a92STim Lee { 37185f2b84eeSEd Tanous severity = message->messageSeverity; 3719d4342a92STim Lee } 3720d4342a92STim Lee 37216f284d24SJiaqing Zhao // Format entry 37226f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37239c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3724ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 3725253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 3726253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 372784afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 372884afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 372984afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 373084afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 37311e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 373284afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 373384afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 373484afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3735647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3736647b3cdcSGeorge Liu { 3737647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3738253f11b8SEd Tanous std::format( 3739253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 3740253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3741647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3742647b3cdcSGeorge Liu } 37436f284d24SJiaqing Zhao 37446f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 37456f284d24SJiaqing Zhao // that entry in this case 37466f284d24SJiaqing Zhao if (codeIndex != 0) 37476f284d24SJiaqing Zhao { 3748ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 37496f284d24SJiaqing Zhao return true; 3750a3316fc6SZhikuiRen } 37516f284d24SJiaqing Zhao 3752ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3753b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 37546f284d24SJiaqing Zhao } 37556f284d24SJiaqing Zhao 37566f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 37576f284d24SJiaqing Zhao return false; 3758a3316fc6SZhikuiRen } 3759a3316fc6SZhikuiRen 3760ac106bf6SEd Tanous static void 3761ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 37626f284d24SJiaqing Zhao const std::string& entryId) 3763a3316fc6SZhikuiRen { 37646f284d24SJiaqing Zhao uint16_t bootIndex = 0; 37656f284d24SJiaqing Zhao uint64_t codeIndex = 0; 37666f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 37676f284d24SJiaqing Zhao { 37686f284d24SJiaqing Zhao // Requested ID was not found 3769ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 37706f284d24SJiaqing Zhao return; 37716f284d24SJiaqing Zhao } 37726f284d24SJiaqing Zhao 37736f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 37746f284d24SJiaqing Zhao { 37756f284d24SJiaqing Zhao // 0 is an invalid index 3776ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 37776f284d24SJiaqing Zhao return; 37786f284d24SJiaqing Zhao } 37796f284d24SJiaqing Zhao 3780a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3781ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 37825e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 37836c9a279eSManojkiran Eda const boost::container::flat_map< 37846c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37856c9a279eSManojkiran Eda postcode) { 3786a3316fc6SZhikuiRen if (ec) 3787a3316fc6SZhikuiRen { 378862598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3789ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3790a3316fc6SZhikuiRen return; 3791a3316fc6SZhikuiRen } 3792a3316fc6SZhikuiRen 3793a3316fc6SZhikuiRen if (postcode.empty()) 3794a3316fc6SZhikuiRen { 3795ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3796a3316fc6SZhikuiRen return; 3797a3316fc6SZhikuiRen } 3798a3316fc6SZhikuiRen 3799ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 38006f284d24SJiaqing Zhao { 3801ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38026f284d24SJiaqing Zhao return; 38036f284d24SJiaqing Zhao } 3804a3316fc6SZhikuiRen }, 380515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 380615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3807a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3808a3316fc6SZhikuiRen bootIndex); 3809a3316fc6SZhikuiRen } 3810a3316fc6SZhikuiRen 3811ac106bf6SEd Tanous static void 3812ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3813ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3814ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3815a3316fc6SZhikuiRen { 3816a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3817ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 38185e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 38196c9a279eSManojkiran Eda const boost::container::flat_map< 38206c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38216c9a279eSManojkiran Eda postcode) { 3822a3316fc6SZhikuiRen if (ec) 3823a3316fc6SZhikuiRen { 382462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3825ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3826a3316fc6SZhikuiRen return; 3827a3316fc6SZhikuiRen } 3828a3316fc6SZhikuiRen 3829a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3830a3316fc6SZhikuiRen if (!postcode.empty()) 3831a3316fc6SZhikuiRen { 3832a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38333648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3834a3316fc6SZhikuiRen { 3835*bd79bce8SPatrick Williams uint64_t thisBootSkip = 3836*bd79bce8SPatrick Williams std::max(static_cast<uint64_t>(skip), entryCount) - 38373648c8beSEd Tanous entryCount; 3838a3316fc6SZhikuiRen uint64_t thisBootTop = 38393648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38403648c8beSEd Tanous entryCount; 3841a3316fc6SZhikuiRen 3842ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3843ac106bf6SEd Tanous thisBootSkip, thisBootTop); 3844a3316fc6SZhikuiRen } 3845ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3846a3316fc6SZhikuiRen } 3847a3316fc6SZhikuiRen 3848a3316fc6SZhikuiRen // continue to previous bootIndex 3849a3316fc6SZhikuiRen if (bootIndex < bootCount) 3850a3316fc6SZhikuiRen { 3851*bd79bce8SPatrick Williams getPostCodeForBoot(asyncResp, 3852*bd79bce8SPatrick Williams static_cast<uint16_t>(bootIndex + 1), 3853a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3854a3316fc6SZhikuiRen } 385581584abeSJiaqing Zhao else if (skip + top < endCount) 3856a3316fc6SZhikuiRen { 3857ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 3858253f11b8SEd Tanous std::format( 3859253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 3860253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3861a3316fc6SZhikuiRen std::to_string(skip + top); 3862a3316fc6SZhikuiRen } 3863a3316fc6SZhikuiRen }, 386415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 386515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3866a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3867a3316fc6SZhikuiRen bootIndex); 3868a3316fc6SZhikuiRen } 3869a3316fc6SZhikuiRen 38708d1b46d7Szhanghch05 static void 3871ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 38723648c8beSEd Tanous size_t skip, size_t top) 3873a3316fc6SZhikuiRen { 3874a3316fc6SZhikuiRen uint64_t entryCount = 0; 38751e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 38761e1e598dSJonathan Doman *crow::connections::systemBus, 38771e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 38781e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 38791e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 3880*bd79bce8SPatrick Williams [asyncResp, entryCount, skip, 3881*bd79bce8SPatrick Williams top](const boost::system::error_code& ec, const uint16_t bootCount) { 3882a3316fc6SZhikuiRen if (ec) 3883a3316fc6SZhikuiRen { 388462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 3885ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3886a3316fc6SZhikuiRen return; 3887a3316fc6SZhikuiRen } 3888ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 38891e1e598dSJonathan Doman }); 3890a3316fc6SZhikuiRen } 3891a3316fc6SZhikuiRen 38927e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3893a3316fc6SZhikuiRen { 38947e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 389522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3896ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 38977e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 389845ca1b86SEd Tanous [&app](const crow::Request& req, 389922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 390022d268cbSEd Tanous const std::string& systemName) { 3901c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3902c937d2bfSEd Tanous .canDelegateTop = true, 3903c937d2bfSEd Tanous .canDelegateSkip = true, 3904c937d2bfSEd Tanous }; 3905c937d2bfSEd Tanous query_param::Query delegatedQuery; 3906c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39073ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 390845ca1b86SEd Tanous { 390945ca1b86SEd Tanous return; 391045ca1b86SEd Tanous } 391125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39127f3e84a1SEd Tanous { 39137f3e84a1SEd Tanous // Option currently returns no systems. TBD 39147f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39157f3e84a1SEd Tanous systemName); 39167f3e84a1SEd Tanous return; 39177f3e84a1SEd Tanous } 391822d268cbSEd Tanous 3919253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 392022d268cbSEd Tanous { 392122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 392222d268cbSEd Tanous systemName); 392322d268cbSEd Tanous return; 392422d268cbSEd Tanous } 3925a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3926a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3927*bd79bce8SPatrick Williams asyncResp->res.jsonValue["@odata.id"] = std::format( 3928*bd79bce8SPatrick Williams "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3929253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3930a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3931a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3932a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3933a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3934a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39353648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 3936*bd79bce8SPatrick Williams size_t top = 3937*bd79bce8SPatrick Williams delegatedQuery.top.value_or(query_param::Query::maxTop); 39383648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39397e860f15SJohn Edward Broadbent }); 3940a3316fc6SZhikuiRen } 3941a3316fc6SZhikuiRen 3942647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3943647b3cdcSGeorge Liu { 39440fda0f12SGeorge Liu BMCWEB_ROUTE( 39450fda0f12SGeorge Liu app, 394622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3947647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3948*bd79bce8SPatrick Williams .methods( 3949*bd79bce8SPatrick Williams boost::beast::http::verb:: 3950*bd79bce8SPatrick Williams get)([&app](const crow::Request& req, 3951647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 395222d268cbSEd Tanous const std::string& systemName, 3953647b3cdcSGeorge Liu const std::string& postCodeID) { 39543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 395545ca1b86SEd Tanous { 395645ca1b86SEd Tanous return; 395745ca1b86SEd Tanous } 395872e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 395999351cd8SEd Tanous req.getHeaderValue("Accept"), 39604a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3961647b3cdcSGeorge Liu { 3962002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3963647b3cdcSGeorge Liu return; 3964647b3cdcSGeorge Liu } 396525b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39667f3e84a1SEd Tanous { 39677f3e84a1SEd Tanous // Option currently returns no systems. TBD 39687f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39697f3e84a1SEd Tanous systemName); 39707f3e84a1SEd Tanous return; 39717f3e84a1SEd Tanous } 3972253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 397322d268cbSEd Tanous { 397422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 397522d268cbSEd Tanous systemName); 397622d268cbSEd Tanous return; 397722d268cbSEd Tanous } 3978647b3cdcSGeorge Liu 3979647b3cdcSGeorge Liu uint64_t currentValue = 0; 3980647b3cdcSGeorge Liu uint16_t index = 0; 3981647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3982647b3cdcSGeorge Liu { 3983*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "LogEntry", 3984*bd79bce8SPatrick Williams postCodeID); 3985647b3cdcSGeorge Liu return; 3986647b3cdcSGeorge Liu } 3987647b3cdcSGeorge Liu 3988647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3989647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 39905e7e2dc5SEd Tanous const boost::system::error_code& ec, 3991*bd79bce8SPatrick Williams const std::vector<std::tuple< 3992*bd79bce8SPatrick Williams uint64_t, std::vector<uint8_t>>>& postcodes) { 3993647b3cdcSGeorge Liu if (ec.value() == EBADR) 3994647b3cdcSGeorge Liu { 3995002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3996002d39b4SEd Tanous postCodeID); 3997647b3cdcSGeorge Liu return; 3998647b3cdcSGeorge Liu } 3999647b3cdcSGeorge Liu if (ec) 4000647b3cdcSGeorge Liu { 400162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4002647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4003647b3cdcSGeorge Liu return; 4004647b3cdcSGeorge Liu } 4005647b3cdcSGeorge Liu 4006647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4007*bd79bce8SPatrick Williams if (value == std::string::npos || 4008*bd79bce8SPatrick Williams postcodes.size() < currentValue) 4009647b3cdcSGeorge Liu { 401062598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4011002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4012002d39b4SEd Tanous postCodeID); 4013647b3cdcSGeorge Liu return; 4014647b3cdcSGeorge Liu } 4015647b3cdcSGeorge Liu 40169eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 401746ff87baSEd Tanous if (c.empty()) 4018647b3cdcSGeorge Liu { 401962598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4020002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4021002d39b4SEd Tanous postCodeID); 4022647b3cdcSGeorge Liu return; 4023647b3cdcSGeorge Liu } 402446ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 402546ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 402646ff87baSEd Tanous std::string_view strData(d, c.size()); 4027647b3cdcSGeorge Liu 4028*bd79bce8SPatrick Williams asyncResp->res.addHeader( 4029*bd79bce8SPatrick Williams boost::beast::http::field::content_type, 4030647b3cdcSGeorge Liu "application/octet-stream"); 4031d9f6c621SEd Tanous asyncResp->res.addHeader( 4032*bd79bce8SPatrick Williams boost::beast::http::field::content_transfer_encoding, 4033*bd79bce8SPatrick Williams "Base64"); 403427b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4035647b3cdcSGeorge Liu }, 4036647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4037647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4038*bd79bce8SPatrick Williams "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", 4039*bd79bce8SPatrick Williams index); 4040647b3cdcSGeorge Liu }); 4041647b3cdcSGeorge Liu } 4042647b3cdcSGeorge Liu 40437e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4044a3316fc6SZhikuiRen { 40457e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 404622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4047ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 404945ca1b86SEd Tanous [&app](const crow::Request& req, 40507e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 405122d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 405345ca1b86SEd Tanous { 405445ca1b86SEd Tanous return; 405545ca1b86SEd Tanous } 405625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 40577f3e84a1SEd Tanous { 40587f3e84a1SEd Tanous // Option currently returns no systems. TBD 40597f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 40607f3e84a1SEd Tanous systemName); 40617f3e84a1SEd Tanous return; 40627f3e84a1SEd Tanous } 4063253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 406422d268cbSEd Tanous { 406522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 406622d268cbSEd Tanous systemName); 406722d268cbSEd Tanous return; 406822d268cbSEd Tanous } 406922d268cbSEd Tanous 40706f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 40717e860f15SJohn Edward Broadbent }); 4072a3316fc6SZhikuiRen } 4073a3316fc6SZhikuiRen 40741da66f75SEd Tanous } // namespace redfish 4075