11da66f75SEd Tanous /* 21da66f75SEd Tanous // Copyright (c) 2018 Intel Corporation 31da66f75SEd Tanous // 41da66f75SEd Tanous // Licensed under the Apache License, Version 2.0 (the "License"); 51da66f75SEd Tanous // you may not use this file except in compliance with the License. 61da66f75SEd Tanous // You may obtain a copy of the License at 71da66f75SEd Tanous // 81da66f75SEd Tanous // http://www.apache.org/licenses/LICENSE-2.0 91da66f75SEd Tanous // 101da66f75SEd Tanous // Unless required by applicable law or agreed to in writing, software 111da66f75SEd Tanous // distributed under the License is distributed on an "AS IS" BASIS, 121da66f75SEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131da66f75SEd Tanous // See the License for the specific language governing permissions and 141da66f75SEd Tanous // limitations under the License. 151da66f75SEd Tanous */ 161da66f75SEd Tanous #pragma once 171da66f75SEd Tanous 183ccb3adbSEd Tanous #include "app.hpp" 197a1dbc48SGeorge Liu #include "dbus_utility.hpp" 203ccb3adbSEd Tanous #include "error_messages.hpp" 2168dd075aSAsmitha Karunanithi #include "generated/enums/log_entry.hpp" 22b7028ebfSSpencer Ku #include "gzfile.hpp" 23647b3cdcSGeorge Liu #include "http_utility.hpp" 24b7028ebfSSpencer Ku #include "human_sort.hpp" 253ccb3adbSEd Tanous #include "query.hpp" 264851d45dSJason M. Bills #include "registries.hpp" 274851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 284851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 293ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 3046229577SJames Feist #include "task.hpp" 315b90429aSEd Tanous #include "task_messages.hpp" 323ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 335b90429aSEd Tanous #include "utils/json_utils.hpp" 343ccb3adbSEd Tanous #include "utils/time_utils.hpp" 351da66f75SEd Tanous 3675e8e218SMyung Bae #include <systemd/sd-id128.h> 37e1f26343SJason M. Bills #include <systemd/sd-journal.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 128df254f2cSEd Tanous inline int getJournalMetadata(sd_journal* journal, std::string_view field, 12939e77504SEd Tanous std::string_view& contents) 13016428a1aSJason M. Bills { 13116428a1aSJason M. Bills const char* data = nullptr; 13216428a1aSJason M. Bills size_t length = 0; 13316428a1aSJason M. Bills int ret = 0; 13416428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 13546ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 13646ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 13746ff87baSEd Tanous 13846ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 13916428a1aSJason M. Bills if (ret < 0) 14016428a1aSJason M. Bills { 14116428a1aSJason M. Bills return ret; 14216428a1aSJason M. Bills } 14339e77504SEd Tanous contents = std::string_view(data, length); 14416428a1aSJason M. Bills // Only use the content after the "=" character. 14581ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 14616428a1aSJason M. Bills return ret; 14716428a1aSJason M. Bills } 14816428a1aSJason M. Bills 149df254f2cSEd Tanous inline int getJournalMetadata(sd_journal* journal, std::string_view field, 150df254f2cSEd Tanous const int& base, long int& contents) 15116428a1aSJason M. Bills { 15216428a1aSJason M. Bills int ret = 0; 15339e77504SEd Tanous std::string_view metadata; 15416428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 15516428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 15616428a1aSJason M. Bills if (ret < 0) 15716428a1aSJason M. Bills { 15816428a1aSJason M. Bills return ret; 15916428a1aSJason M. Bills } 160b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 16116428a1aSJason M. Bills return ret; 16216428a1aSJason M. Bills } 16316428a1aSJason M. Bills 164df254f2cSEd Tanous inline bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp) 165a3316fc6SZhikuiRen { 166a3316fc6SZhikuiRen int ret = 0; 167a3316fc6SZhikuiRen uint64_t timestamp = 0; 168a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 169a3316fc6SZhikuiRen if (ret < 0) 170a3316fc6SZhikuiRen { 17162598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 172a3316fc6SZhikuiRen return false; 173a3316fc6SZhikuiRen } 174e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1759c620e21SAsmitha Karunanithi return true; 176a3316fc6SZhikuiRen } 17750b8a43aSEd Tanous 178df254f2cSEd Tanous inline bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 179e85d6b16SJason M. Bills const bool firstEntry = true) 18016428a1aSJason M. Bills { 18116428a1aSJason M. Bills int ret = 0; 18275e8e218SMyung Bae static sd_id128_t prevBootID{}; 18316428a1aSJason M. Bills static uint64_t prevTs = 0; 18416428a1aSJason M. Bills static int index = 0; 185e85d6b16SJason M. Bills if (firstEntry) 186e85d6b16SJason M. Bills { 18775e8e218SMyung Bae prevBootID = {}; 188e85d6b16SJason M. Bills prevTs = 0; 189e85d6b16SJason M. Bills } 190e85d6b16SJason M. Bills 19116428a1aSJason M. Bills // Get the entry timestamp 19216428a1aSJason M. Bills uint64_t curTs = 0; 19375e8e218SMyung Bae sd_id128_t curBootID{}; 19475e8e218SMyung Bae ret = sd_journal_get_monotonic_usec(journal, &curTs, &curBootID); 19516428a1aSJason M. Bills if (ret < 0) 19616428a1aSJason M. Bills { 19762598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 19816428a1aSJason M. Bills return false; 19916428a1aSJason M. Bills } 20075e8e218SMyung Bae // If the timestamp isn't unique on the same boot, increment the index 20175e8e218SMyung Bae bool sameBootIDs = sd_id128_equal(curBootID, prevBootID) != 0; 20275e8e218SMyung Bae if (sameBootIDs && (curTs == prevTs)) 20316428a1aSJason M. Bills { 20416428a1aSJason M. Bills index++; 20516428a1aSJason M. Bills } 20616428a1aSJason M. Bills else 20716428a1aSJason M. Bills { 20816428a1aSJason M. Bills // Otherwise, reset it 20916428a1aSJason M. Bills index = 0; 21016428a1aSJason M. Bills } 21175e8e218SMyung Bae 21275e8e218SMyung Bae if (!sameBootIDs) 21375e8e218SMyung Bae { 21475e8e218SMyung Bae // Save the bootID 21575e8e218SMyung Bae prevBootID = curBootID; 21675e8e218SMyung Bae } 21716428a1aSJason M. Bills // Save the timestamp 21816428a1aSJason M. Bills prevTs = curTs; 21916428a1aSJason M. Bills 22075e8e218SMyung Bae // make entryID as <bootID>_<timestamp>[_<index>] 22175e8e218SMyung Bae std::array<char, SD_ID128_STRING_MAX> bootIDStr{}; 22275e8e218SMyung Bae sd_id128_to_string(curBootID, bootIDStr.data()); 22375e8e218SMyung Bae entryID = std::format("{}_{}", bootIDStr.data(), curTs); 22416428a1aSJason M. Bills if (index > 0) 22516428a1aSJason M. Bills { 22616428a1aSJason M. Bills entryID += "_" + std::to_string(index); 22716428a1aSJason M. Bills } 22816428a1aSJason M. Bills return true; 22916428a1aSJason M. Bills } 23016428a1aSJason M. Bills 231e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 232e85d6b16SJason M. Bills const bool firstEntry = true) 23395820184SJason M. Bills { 234271584abSEd Tanous static time_t prevTs = 0; 23595820184SJason M. Bills static int index = 0; 236e85d6b16SJason M. Bills if (firstEntry) 237e85d6b16SJason M. Bills { 238e85d6b16SJason M. Bills prevTs = 0; 239e85d6b16SJason M. Bills } 240e85d6b16SJason M. Bills 24195820184SJason M. Bills // Get the entry timestamp 242271584abSEd Tanous std::time_t curTs = 0; 24395820184SJason M. Bills std::tm timeStruct = {}; 24495820184SJason M. Bills std::istringstream entryStream(logEntry); 24595820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 24695820184SJason M. Bills { 24795820184SJason M. Bills curTs = std::mktime(&timeStruct); 24895820184SJason M. Bills } 24995820184SJason M. Bills // If the timestamp isn't unique, increment the index 25095820184SJason M. Bills if (curTs == prevTs) 25195820184SJason M. Bills { 25295820184SJason M. Bills index++; 25395820184SJason M. Bills } 25495820184SJason M. Bills else 25595820184SJason M. Bills { 25695820184SJason M. Bills // Otherwise, reset it 25795820184SJason M. Bills index = 0; 25895820184SJason M. Bills } 25995820184SJason M. Bills // Save the timestamp 26095820184SJason M. Bills prevTs = curTs; 26195820184SJason M. Bills 26295820184SJason M. Bills entryID = std::to_string(curTs); 26395820184SJason M. Bills if (index > 0) 26495820184SJason M. Bills { 26595820184SJason M. Bills entryID += "_" + std::to_string(index); 26695820184SJason M. Bills } 26795820184SJason M. Bills return true; 26895820184SJason M. Bills } 26995820184SJason M. Bills 27075e8e218SMyung Bae // Entry is formed like "BootID_timestamp" or "BootID_timestamp_index" 271df254f2cSEd Tanous inline bool 2728d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 273099984c1SEd Tanous std::string_view entryIDStrView, sd_id128_t& bootID, 27475e8e218SMyung Bae uint64_t& timestamp, uint64_t& index) 27516428a1aSJason M. Bills { 27675e8e218SMyung Bae // Convert the unique ID back to a bootID + timestamp to find the entry 27775e8e218SMyung Bae auto underscore1Pos = entryIDStrView.find('_'); 27875e8e218SMyung Bae if (underscore1Pos == std::string_view::npos) 27975e8e218SMyung Bae { 28075e8e218SMyung Bae // EntryID has no bootID or timestamp 281099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 28275e8e218SMyung Bae return false; 28375e8e218SMyung Bae } 28475e8e218SMyung Bae 28575e8e218SMyung Bae // EntryID has bootID + timestamp 28675e8e218SMyung Bae 28775e8e218SMyung Bae // Convert entryIDViewString to BootID 28875e8e218SMyung Bae // NOTE: bootID string which needs to be null-terminated for 28975e8e218SMyung Bae // sd_id128_from_string() 290099984c1SEd Tanous std::string bootIDStr(entryIDStrView.substr(0, underscore1Pos)); 29175e8e218SMyung Bae if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0) 29275e8e218SMyung Bae { 293099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 29475e8e218SMyung Bae return false; 29575e8e218SMyung Bae } 29675e8e218SMyung Bae 29775e8e218SMyung Bae // Get the timestamp from entryID 298099984c1SEd Tanous entryIDStrView.remove_prefix(underscore1Pos + 1); 29975e8e218SMyung Bae 300099984c1SEd Tanous auto [timestampEnd, tstampEc] = std::from_chars( 301099984c1SEd Tanous entryIDStrView.begin(), entryIDStrView.end(), timestamp); 302099984c1SEd Tanous if (tstampEc != std::errc()) 30316428a1aSJason M. Bills { 304099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 30516428a1aSJason M. Bills return false; 30616428a1aSJason M. Bills } 307099984c1SEd Tanous entryIDStrView = std::string_view( 308099984c1SEd Tanous timestampEnd, 309099984c1SEd Tanous static_cast<size_t>(std::distance(timestampEnd, entryIDStrView.end()))); 310099984c1SEd Tanous if (entryIDStrView.empty()) 31116428a1aSJason M. Bills { 312099984c1SEd Tanous index = 0U; 313099984c1SEd Tanous return true; 314099984c1SEd Tanous } 315099984c1SEd Tanous // Timestamp might include optional index, if two events happened at the 316099984c1SEd Tanous // same "time". 317099984c1SEd Tanous if (entryIDStrView[0] != '_') 318099984c1SEd Tanous { 319099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 320099984c1SEd Tanous return false; 321099984c1SEd Tanous } 322099984c1SEd Tanous entryIDStrView.remove_prefix(1); 323099984c1SEd Tanous auto [ptr, indexEc] = std::from_chars(entryIDStrView.begin(), 324099984c1SEd Tanous entryIDStrView.end(), index); 325099984c1SEd Tanous if (indexEc != std::errc() || ptr != entryIDStrView.end()) 326099984c1SEd Tanous { 327099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 32816428a1aSJason M. Bills return false; 32916428a1aSJason M. Bills } 33016428a1aSJason M. Bills return true; 33116428a1aSJason M. Bills } 33216428a1aSJason M. Bills 33395820184SJason M. Bills static bool 33495820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 33595820184SJason M. Bills { 33695820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 33795820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 33895820184SJason M. Bills 33995820184SJason M. Bills // Loop through the directory looking for redfish log files 34095820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 34195820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 34295820184SJason M. Bills { 34395820184SJason M. Bills // If we find a redfish log file, save the path 34495820184SJason M. Bills std::string filename = dirEnt.path().filename(); 34511ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 34695820184SJason M. Bills { 34795820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 34895820184SJason M. Bills } 34995820184SJason M. Bills } 35095820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 35195820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 35295820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 3533544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 35495820184SJason M. Bills 35595820184SJason M. Bills return !redfishLogFiles.empty(); 35695820184SJason M. Bills } 35795820184SJason M. Bills 35868dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 35968dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 36068dd075aSAsmitha Karunanithi { 36168dd075aSAsmitha Karunanithi if (originatorType == 36268dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 36368dd075aSAsmitha Karunanithi { 36468dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 36568dd075aSAsmitha Karunanithi } 36668dd075aSAsmitha Karunanithi if (originatorType == 36768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 36868dd075aSAsmitha Karunanithi { 36968dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 37068dd075aSAsmitha Karunanithi } 37168dd075aSAsmitha Karunanithi if (originatorType == 37268dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 37368dd075aSAsmitha Karunanithi { 37468dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 37568dd075aSAsmitha Karunanithi } 37668dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 37768dd075aSAsmitha Karunanithi } 37868dd075aSAsmitha Karunanithi 379aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3802d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 381c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 38268dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 383aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 386aefe3786SClaire Weinan { 387aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 388aefe3786SClaire Weinan { 389aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 390aefe3786SClaire Weinan { 391aefe3786SClaire Weinan if (propertyMap.first == "Status") 392aefe3786SClaire Weinan { 393aefe3786SClaire Weinan const auto* status = 394aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 395aefe3786SClaire Weinan if (status == nullptr) 396aefe3786SClaire Weinan { 397aefe3786SClaire Weinan messages::internalError(asyncResp->res); 398aefe3786SClaire Weinan break; 399aefe3786SClaire Weinan } 400aefe3786SClaire Weinan dumpStatus = *status; 401aefe3786SClaire Weinan } 402aefe3786SClaire Weinan } 403aefe3786SClaire Weinan } 404aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 405aefe3786SClaire Weinan { 406aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 407aefe3786SClaire Weinan { 408aefe3786SClaire Weinan if (propertyMap.first == "Size") 409aefe3786SClaire Weinan { 410aefe3786SClaire Weinan const auto* sizePtr = 411aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 412aefe3786SClaire Weinan if (sizePtr == nullptr) 413aefe3786SClaire Weinan { 414aefe3786SClaire Weinan messages::internalError(asyncResp->res); 415aefe3786SClaire Weinan break; 416aefe3786SClaire Weinan } 417aefe3786SClaire Weinan size = *sizePtr; 418aefe3786SClaire Weinan break; 419aefe3786SClaire Weinan } 420aefe3786SClaire Weinan } 421aefe3786SClaire Weinan } 422aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 423aefe3786SClaire Weinan { 424aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 425aefe3786SClaire Weinan { 426aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 427aefe3786SClaire Weinan { 428aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 429aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 430aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 431aefe3786SClaire Weinan { 432aefe3786SClaire Weinan messages::internalError(asyncResp->res); 433aefe3786SClaire Weinan break; 434aefe3786SClaire Weinan } 435c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 436aefe3786SClaire Weinan break; 437aefe3786SClaire Weinan } 438aefe3786SClaire Weinan } 439aefe3786SClaire Weinan } 44068dd075aSAsmitha Karunanithi else if (interfaceMap.first == 44168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 44268dd075aSAsmitha Karunanithi { 44368dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 44468dd075aSAsmitha Karunanithi { 44568dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 44668dd075aSAsmitha Karunanithi { 44768dd075aSAsmitha Karunanithi const std::string* id = 44868dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 44968dd075aSAsmitha Karunanithi if (id == nullptr) 45068dd075aSAsmitha Karunanithi { 45168dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 45268dd075aSAsmitha Karunanithi break; 45368dd075aSAsmitha Karunanithi } 45468dd075aSAsmitha Karunanithi originatorId = *id; 45568dd075aSAsmitha Karunanithi } 45668dd075aSAsmitha Karunanithi 45768dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 45868dd075aSAsmitha Karunanithi { 45968dd075aSAsmitha Karunanithi const std::string* type = 46068dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 46168dd075aSAsmitha Karunanithi if (type == nullptr) 46268dd075aSAsmitha Karunanithi { 46368dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46468dd075aSAsmitha Karunanithi break; 46568dd075aSAsmitha Karunanithi } 46668dd075aSAsmitha Karunanithi 46768dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 46868dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 46968dd075aSAsmitha Karunanithi { 47068dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 47168dd075aSAsmitha Karunanithi break; 47268dd075aSAsmitha Karunanithi } 47368dd075aSAsmitha Karunanithi } 47468dd075aSAsmitha Karunanithi } 47568dd075aSAsmitha Karunanithi } 476aefe3786SClaire Weinan } 477aefe3786SClaire Weinan } 478aefe3786SClaire Weinan 47921ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 480fdd26906SClaire Weinan { 481fdd26906SClaire Weinan std::string entriesPath; 482fdd26906SClaire Weinan 483fdd26906SClaire Weinan if (dumpType == "BMC") 484fdd26906SClaire Weinan { 485*253f11b8SEd Tanous entriesPath = 486*253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 487*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 488fdd26906SClaire Weinan } 489fdd26906SClaire Weinan else if (dumpType == "FaultLog") 490fdd26906SClaire Weinan { 491*253f11b8SEd Tanous entriesPath = 492*253f11b8SEd Tanous std::format("/redfish/v1/Managers/{}/LogServices/FaultLog/Entries/", 493*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 494fdd26906SClaire Weinan } 495fdd26906SClaire Weinan else if (dumpType == "System") 496fdd26906SClaire Weinan { 497*253f11b8SEd Tanous entriesPath = 498*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 499*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 500fdd26906SClaire Weinan } 501fdd26906SClaire Weinan else 502fdd26906SClaire Weinan { 50362598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 50462598e31SEd Tanous dumpType); 505fdd26906SClaire Weinan } 506fdd26906SClaire Weinan 507fdd26906SClaire Weinan // Returns empty string on error 508fdd26906SClaire Weinan return entriesPath; 509fdd26906SClaire Weinan } 510fdd26906SClaire Weinan 5118d1b46d7Szhanghch05 inline void 5128d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5135cb1dd27SAsmitha Karunanithi const std::string& dumpType) 5145cb1dd27SAsmitha Karunanithi { 515fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 516fdd26906SClaire Weinan if (entriesPath.empty()) 5175cb1dd27SAsmitha Karunanithi { 5185cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5195cb1dd27SAsmitha Karunanithi return; 5205cb1dd27SAsmitha Karunanithi } 5215cb1dd27SAsmitha Karunanithi 5225eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5235eb468daSGeorge Liu dbus::utility::getManagedObjects( 5245eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 525fdd26906SClaire Weinan [asyncResp, entriesPath, 5265e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 5275eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 5285cb1dd27SAsmitha Karunanithi if (ec) 5295cb1dd27SAsmitha Karunanithi { 53062598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5315cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5325cb1dd27SAsmitha Karunanithi return; 5335cb1dd27SAsmitha Karunanithi } 5345cb1dd27SAsmitha Karunanithi 535fdd26906SClaire Weinan // Remove ending slash 536fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 537fdd26906SClaire Weinan if (!odataIdStr.empty()) 538fdd26906SClaire Weinan { 539fdd26906SClaire Weinan odataIdStr.pop_back(); 540fdd26906SClaire Weinan } 541fdd26906SClaire Weinan 542fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 543fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 544fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 545fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 54689492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 54789492a15SPatrick Williams " Dump Entries"; 548fdd26906SClaire Weinan 5493544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 55018f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 5515cb1dd27SAsmitha Karunanithi 5525eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 5533544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 554002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 555002d39b4SEd Tanous r.first.filename()); 556565dfb6fSClaire Weinan }); 557565dfb6fSClaire Weinan 5585cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5595cb1dd27SAsmitha Karunanithi { 560b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5615cb1dd27SAsmitha Karunanithi { 5625cb1dd27SAsmitha Karunanithi continue; 5635cb1dd27SAsmitha Karunanithi } 564c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5655cb1dd27SAsmitha Karunanithi uint64_t size = 0; 56635440d18SAsmitha Karunanithi std::string dumpStatus; 56768dd075aSAsmitha Karunanithi std::string originatorId; 56868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 56968dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 570433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5712dfd18efSEd Tanous 5722dfd18efSEd Tanous std::string entryID = object.first.filename(); 5732dfd18efSEd Tanous if (entryID.empty()) 5745cb1dd27SAsmitha Karunanithi { 5755cb1dd27SAsmitha Karunanithi continue; 5765cb1dd27SAsmitha Karunanithi } 5775cb1dd27SAsmitha Karunanithi 578c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 57968dd075aSAsmitha Karunanithi originatorId, originatorType, 580aefe3786SClaire Weinan asyncResp); 5815cb1dd27SAsmitha Karunanithi 5820fda0f12SGeorge Liu if (dumpStatus != 5830fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 58435440d18SAsmitha Karunanithi !dumpStatus.empty()) 58535440d18SAsmitha Karunanithi { 58635440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 58735440d18SAsmitha Karunanithi continue; 58835440d18SAsmitha Karunanithi } 58935440d18SAsmitha Karunanithi 59068dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 591fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5925cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5935cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5945cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 595bbd80db8SClaire Weinan thisEntry["Created"] = 596bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5975cb1dd27SAsmitha Karunanithi 59868dd075aSAsmitha Karunanithi if (!originatorId.empty()) 59968dd075aSAsmitha Karunanithi { 60068dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 60168dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 60268dd075aSAsmitha Karunanithi } 60368dd075aSAsmitha Karunanithi 6045cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6055cb1dd27SAsmitha Karunanithi { 606d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 60789492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 60889492a15SPatrick Williams "/attachment"; 609fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6105cb1dd27SAsmitha Karunanithi } 6115cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6125cb1dd27SAsmitha Karunanithi { 613d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 614d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 61589492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 61689492a15SPatrick Williams "/attachment"; 617fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6185cb1dd27SAsmitha Karunanithi } 619b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 6205cb1dd27SAsmitha Karunanithi } 621002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 6223544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 6235eb468daSGeorge Liu }); 6245cb1dd27SAsmitha Karunanithi } 6255cb1dd27SAsmitha Karunanithi 6268d1b46d7Szhanghch05 inline void 627c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6288d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 6295cb1dd27SAsmitha Karunanithi { 630fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 631fdd26906SClaire Weinan if (entriesPath.empty()) 6325cb1dd27SAsmitha Karunanithi { 6335cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6345cb1dd27SAsmitha Karunanithi return; 6355cb1dd27SAsmitha Karunanithi } 6365cb1dd27SAsmitha Karunanithi 6375eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 6385eb468daSGeorge Liu dbus::utility::getManagedObjects( 6395eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 640fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 6415e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 64202cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 6435cb1dd27SAsmitha Karunanithi if (ec) 6445cb1dd27SAsmitha Karunanithi { 64562598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 6465cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6475cb1dd27SAsmitha Karunanithi return; 6485cb1dd27SAsmitha Karunanithi } 6495cb1dd27SAsmitha Karunanithi 650b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 65118f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 652b47452b2SAsmitha Karunanithi 6539eb808c1SEd Tanous for (const auto& objectPath : resp) 6545cb1dd27SAsmitha Karunanithi { 655b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6565cb1dd27SAsmitha Karunanithi { 6575cb1dd27SAsmitha Karunanithi continue; 6585cb1dd27SAsmitha Karunanithi } 6595cb1dd27SAsmitha Karunanithi 6605cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 661c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6625cb1dd27SAsmitha Karunanithi uint64_t size = 0; 66335440d18SAsmitha Karunanithi std::string dumpStatus; 66468dd075aSAsmitha Karunanithi std::string originatorId; 66568dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 66668dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6675cb1dd27SAsmitha Karunanithi 668aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 66968dd075aSAsmitha Karunanithi timestampUs, originatorId, 67068dd075aSAsmitha Karunanithi originatorType, asyncResp); 6715cb1dd27SAsmitha Karunanithi 6720fda0f12SGeorge Liu if (dumpStatus != 6730fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 67435440d18SAsmitha Karunanithi !dumpStatus.empty()) 67535440d18SAsmitha Karunanithi { 67635440d18SAsmitha Karunanithi // Dump status is not Complete 67735440d18SAsmitha Karunanithi // return not found until status is changed to Completed 678d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 679d1bde9e5SKrzysztof Grobelny entryID); 68035440d18SAsmitha Karunanithi return; 68135440d18SAsmitha Karunanithi } 68235440d18SAsmitha Karunanithi 6835cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 68468dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 685fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6865cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6875cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6885cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 689bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 690bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6915cb1dd27SAsmitha Karunanithi 69268dd075aSAsmitha Karunanithi if (!originatorId.empty()) 69368dd075aSAsmitha Karunanithi { 69468dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 69568dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 69668dd075aSAsmitha Karunanithi } 69768dd075aSAsmitha Karunanithi 6985cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6995cb1dd27SAsmitha Karunanithi { 700d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 701d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 702fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 703fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7045cb1dd27SAsmitha Karunanithi } 7055cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 7065cb1dd27SAsmitha Karunanithi { 707d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 708002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 709d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 710fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 711fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7125cb1dd27SAsmitha Karunanithi } 7135cb1dd27SAsmitha Karunanithi } 714e05aec50SEd Tanous if (!foundDumpEntry) 715b47452b2SAsmitha Karunanithi { 71662598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 717b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 718b90d14f2SMyung Bae entryID); 719b47452b2SAsmitha Karunanithi return; 720b47452b2SAsmitha Karunanithi } 7215eb468daSGeorge Liu }); 7225cb1dd27SAsmitha Karunanithi } 7235cb1dd27SAsmitha Karunanithi 7248d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7259878256fSStanley Chu const std::string& entryID, 726b47452b2SAsmitha Karunanithi const std::string& dumpType) 7275cb1dd27SAsmitha Karunanithi { 7285a39f77aSPatrick Williams auto respHandler = [asyncResp, 7295a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 73062598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 7315cb1dd27SAsmitha Karunanithi if (ec) 7325cb1dd27SAsmitha Karunanithi { 7333de8d8baSGeorge Liu if (ec.value() == EBADR) 7343de8d8baSGeorge Liu { 7353de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 7363de8d8baSGeorge Liu return; 7373de8d8baSGeorge Liu } 73862598e31SEd Tanous BMCWEB_LOG_ERROR( 73962598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 74062598e31SEd Tanous entryID); 7415cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 7425cb1dd27SAsmitha Karunanithi return; 7435cb1dd27SAsmitha Karunanithi } 7445cb1dd27SAsmitha Karunanithi }; 74518f8f608SEd Tanous 7465cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7475cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 74818f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 7495cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7505cb1dd27SAsmitha Karunanithi } 751b5f288d2SAbhilash Raju inline bool checkSizeLimit(int fd, crow::Response& res) 752b5f288d2SAbhilash Raju { 753b5f288d2SAbhilash Raju long long int size = lseek(fd, 0, SEEK_END); 754b5f288d2SAbhilash Raju if (size <= 0) 755b5f288d2SAbhilash Raju { 756b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 757b5f288d2SAbhilash Raju size); 758b5f288d2SAbhilash Raju messages::internalError(res); 759b5f288d2SAbhilash Raju return false; 760b5f288d2SAbhilash Raju } 7615cb1dd27SAsmitha Karunanithi 762b5f288d2SAbhilash Raju // Arbitrary max size of 20MB to accommodate BMC dumps 763b5f288d2SAbhilash Raju constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 764b5f288d2SAbhilash Raju if (size > maxFileSize) 765b5f288d2SAbhilash Raju { 766b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 767b5f288d2SAbhilash Raju size, maxFileSize); 768b5f288d2SAbhilash Raju messages::internalError(res); 769b5f288d2SAbhilash Raju return false; 770b5f288d2SAbhilash Raju } 771b5f288d2SAbhilash Raju off_t rc = lseek(fd, 0, SEEK_SET); 772b5f288d2SAbhilash Raju if (rc < 0) 773b5f288d2SAbhilash Raju { 774b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 775b5f288d2SAbhilash Raju messages::internalError(res); 776b5f288d2SAbhilash Raju return false; 777b5f288d2SAbhilash Raju } 778b5f288d2SAbhilash Raju return true; 779b5f288d2SAbhilash Raju } 780168d1b1aSCarson Labrado inline void 781168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 782168d1b1aSCarson Labrado const std::string& entryID, 783168d1b1aSCarson Labrado const std::string& downloadEntryType, 784168d1b1aSCarson Labrado const boost::system::error_code& ec, 785168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 786168d1b1aSCarson Labrado { 787168d1b1aSCarson Labrado if (ec.value() == EBADR) 788168d1b1aSCarson Labrado { 789168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 790168d1b1aSCarson Labrado return; 791168d1b1aSCarson Labrado } 792168d1b1aSCarson Labrado if (ec) 793168d1b1aSCarson Labrado { 794168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 795168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 796168d1b1aSCarson Labrado return; 797168d1b1aSCarson Labrado } 798168d1b1aSCarson Labrado 799168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 800168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 801168d1b1aSCarson Labrado { 802168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 803168d1b1aSCarson Labrado downloadEntryType); 804168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 805168d1b1aSCarson Labrado } 806168d1b1aSCarson Labrado 807168d1b1aSCarson Labrado int fd = -1; 808168d1b1aSCarson Labrado fd = dup(unixfd); 809168d1b1aSCarson Labrado if (fd < 0) 810168d1b1aSCarson Labrado { 811168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 812168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 813168d1b1aSCarson Labrado return; 814168d1b1aSCarson Labrado } 815b5f288d2SAbhilash Raju if (!checkSizeLimit(fd, asyncResp->res)) 816168d1b1aSCarson Labrado { 817168d1b1aSCarson Labrado close(fd); 818168d1b1aSCarson Labrado return; 819168d1b1aSCarson Labrado } 820168d1b1aSCarson Labrado if (downloadEntryType == "System") 821168d1b1aSCarson Labrado { 822b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 823b5f288d2SAbhilash Raju { 824b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 825b5f288d2SAbhilash Raju close(fd); 826b5f288d2SAbhilash Raju return; 827b5f288d2SAbhilash Raju } 828168d1b1aSCarson Labrado asyncResp->res.addHeader( 829168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 830b5f288d2SAbhilash Raju return; 831168d1b1aSCarson Labrado } 832b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd)) 83327b0cf90SEd Tanous { 834b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 835b5f288d2SAbhilash Raju close(fd); 836b5f288d2SAbhilash Raju return; 83727b0cf90SEd Tanous } 838168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 839168d1b1aSCarson Labrado "application/octet-stream"); 840168d1b1aSCarson Labrado } 841168d1b1aSCarson Labrado 842168d1b1aSCarson Labrado inline void 843168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 844168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 845168d1b1aSCarson Labrado { 846168d1b1aSCarson Labrado if (dumpType != "BMC") 847168d1b1aSCarson Labrado { 848168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 849168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 850168d1b1aSCarson Labrado return; 851168d1b1aSCarson Labrado } 852168d1b1aSCarson Labrado 85318f8f608SEd Tanous std::string dumpEntryPath = std::format("{}/entry/{}", 85418f8f608SEd Tanous getDumpPath(dumpType), entryID); 855168d1b1aSCarson Labrado 856168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 857168d1b1aSCarson Labrado [asyncResp, entryID, 858168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 859168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 860168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 861168d1b1aSCarson Labrado }; 862168d1b1aSCarson Labrado 863168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 864168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 865168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 866168d1b1aSCarson Labrado } 867168d1b1aSCarson Labrado 868168d1b1aSCarson Labrado inline void 869168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 870168d1b1aSCarson Labrado const std::string& systemName, 871168d1b1aSCarson Labrado const std::string& entryID, 872168d1b1aSCarson Labrado const std::string& dumpType) 873168d1b1aSCarson Labrado { 87425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 875168d1b1aSCarson Labrado { 876168d1b1aSCarson Labrado // Option currently returns no systems. TBD 877168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 878168d1b1aSCarson Labrado systemName); 879168d1b1aSCarson Labrado return; 880168d1b1aSCarson Labrado } 881*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 882168d1b1aSCarson Labrado { 883168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 884168d1b1aSCarson Labrado systemName); 885168d1b1aSCarson Labrado return; 886168d1b1aSCarson Labrado } 887168d1b1aSCarson Labrado 888168d1b1aSCarson Labrado std::string entryPath = 889168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 890168d1b1aSCarson Labrado entryID; 891168d1b1aSCarson Labrado 892168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 893168d1b1aSCarson Labrado [asyncResp, entryID, 894168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 895168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 896168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 897168d1b1aSCarson Labrado }; 898168d1b1aSCarson Labrado 899168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 900168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 901168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 902168d1b1aSCarson Labrado } 903168d1b1aSCarson Labrado 9048e31778eSAsmitha Karunanithi inline DumpCreationProgress 9058e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 906a43be80fSAsmitha Karunanithi { 9078e31778eSAsmitha Karunanithi if (status == 9088e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 9098e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 9108e31778eSAsmitha Karunanithi { 9118e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9128e31778eSAsmitha Karunanithi } 9138e31778eSAsmitha Karunanithi if (status == 9148e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 9158e31778eSAsmitha Karunanithi { 9168e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 9178e31778eSAsmitha Karunanithi } 9188e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9198e31778eSAsmitha Karunanithi } 9208e31778eSAsmitha Karunanithi 9218e31778eSAsmitha Karunanithi inline DumpCreationProgress 9228e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 9238e31778eSAsmitha Karunanithi { 9248e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 9258e31778eSAsmitha Karunanithi { 9268e31778eSAsmitha Karunanithi if (key == "Status") 9278e31778eSAsmitha Karunanithi { 9288e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 9298e31778eSAsmitha Karunanithi if (value == nullptr) 9308e31778eSAsmitha Karunanithi { 93162598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 9328e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9338e31778eSAsmitha Karunanithi } 9348e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 9358e31778eSAsmitha Karunanithi } 9368e31778eSAsmitha Karunanithi } 9378e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9388e31778eSAsmitha Karunanithi } 9398e31778eSAsmitha Karunanithi 9408e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 9418e31778eSAsmitha Karunanithi { 9428e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 9438e31778eSAsmitha Karunanithi { 944*253f11b8SEd Tanous return std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/", 945*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 9468e31778eSAsmitha Karunanithi } 9478e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 9488e31778eSAsmitha Karunanithi { 949*253f11b8SEd Tanous return std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/", 950*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 9518e31778eSAsmitha Karunanithi } 9528e31778eSAsmitha Karunanithi return ""; 9538e31778eSAsmitha Karunanithi } 9548e31778eSAsmitha Karunanithi 9558e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 9568e31778eSAsmitha Karunanithi task::Payload&& payload, 9578e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9588e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 9598e31778eSAsmitha Karunanithi { 9608e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 9618e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 9628e31778eSAsmitha Karunanithi 9638e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 9648e31778eSAsmitha Karunanithi 9658e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 9668e31778eSAsmitha Karunanithi { 96762598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 9688e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9698e31778eSAsmitha Karunanithi return; 9708e31778eSAsmitha Karunanithi } 9718e31778eSAsmitha Karunanithi 9728e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9738cb2c024SEd Tanous [asyncResp, payload = std::move(payload), createdObjPath, 9748e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 9755e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 9768e31778eSAsmitha Karunanithi const std::string& introspectXml) { 9778e31778eSAsmitha Karunanithi if (ec) 9788e31778eSAsmitha Karunanithi { 97962598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 98062598e31SEd Tanous ec.message()); 9818e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9828e31778eSAsmitha Karunanithi return; 9838e31778eSAsmitha Karunanithi } 9848e31778eSAsmitha Karunanithi 9858e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 9868e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 9878e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 9888e31778eSAsmitha Karunanithi // Else, return task completed. 9898e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 9908e31778eSAsmitha Karunanithi 9918e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 9928e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 9938e31778eSAsmitha Karunanithi if (pRoot == nullptr) 9948e31778eSAsmitha Karunanithi { 99562598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 9968e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9978e31778eSAsmitha Karunanithi return; 9988e31778eSAsmitha Karunanithi } 9998e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 10008e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 10018e31778eSAsmitha Karunanithi 10028e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 10038e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 10048e31778eSAsmitha Karunanithi { 10058e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 10068e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 10078e31778eSAsmitha Karunanithi { 10088e31778eSAsmitha Karunanithi if (thisInterfaceName == 10098e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 10108e31778eSAsmitha Karunanithi { 10118e31778eSAsmitha Karunanithi interfaceNode = 10128e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 10138e31778eSAsmitha Karunanithi continue; 10148e31778eSAsmitha Karunanithi } 10158e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 10168e31778eSAsmitha Karunanithi break; 10178e31778eSAsmitha Karunanithi } 10188e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 10198e31778eSAsmitha Karunanithi } 10208e31778eSAsmitha Karunanithi 1021a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 10228e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 10238b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 1024a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 10258b24275dSEd Tanous if (ec2) 1026cb13a392SEd Tanous { 102762598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 102862598e31SEd Tanous createdObjPath.str); 10298e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 10306145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 10316145ed6fSAsmitha Karunanithi return task::completed; 1032cb13a392SEd Tanous } 1033b9d36b47SEd Tanous 10348e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 1035a43be80fSAsmitha Karunanithi { 10368e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 10378e31778eSAsmitha Karunanithi std::string prop; 10388e31778eSAsmitha Karunanithi msg.read(prop, values); 10398e31778eSAsmitha Karunanithi 10408e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 10418e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 10428e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 10438e31778eSAsmitha Karunanithi { 104462598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 104562598e31SEd Tanous createdObjPath.str); 10468e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 10478e31778eSAsmitha Karunanithi return task::completed; 10488e31778eSAsmitha Karunanithi } 10498e31778eSAsmitha Karunanithi 10508e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 10518e31778eSAsmitha Karunanithi { 105262598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 105362598e31SEd Tanous createdObjPath.str); 10548e31778eSAsmitha Karunanithi return !task::completed; 10558e31778eSAsmitha Karunanithi } 10568e31778eSAsmitha Karunanithi } 10578e31778eSAsmitha Karunanithi 1058a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 1059a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 1060a43be80fSAsmitha Karunanithi 1061c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 1062*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump/Entries/{}", 1063*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, dumpId); 1064c51a58eeSEd Tanous 1065c51a58eeSEd Tanous std::string headerLoc = "Location: "; 1066c51a58eeSEd Tanous headerLoc += url.buffer(); 1067c51a58eeSEd Tanous 1068002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 1069a43be80fSAsmitha Karunanithi 107062598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 107162598e31SEd Tanous createdObjPath.str); 1072a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 1073b47452b2SAsmitha Karunanithi return task::completed; 1074a43be80fSAsmitha Karunanithi }, 10758e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 10768e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 10778e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 1078a43be80fSAsmitha Karunanithi 10798e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 10808e31778eSAsmitha Karunanithi // requested dump will be collected. 10818e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 1082a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 10838e31778eSAsmitha Karunanithi task->payload.emplace(payload); 10848e31778eSAsmitha Karunanithi }, 10858e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 10868e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 1087a43be80fSAsmitha Karunanithi } 1088a43be80fSAsmitha Karunanithi 10898d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10908d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 1091a43be80fSAsmitha Karunanithi { 1092fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 1093fdd26906SClaire Weinan if (dumpPath.empty()) 1094a43be80fSAsmitha Karunanithi { 1095a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1096a43be80fSAsmitha Karunanithi return; 1097a43be80fSAsmitha Karunanithi } 1098a43be80fSAsmitha Karunanithi 1099a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 1100a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 1101a43be80fSAsmitha Karunanithi 110215ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 1103a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 1104a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 1105a43be80fSAsmitha Karunanithi { 1106a43be80fSAsmitha Karunanithi return; 1107a43be80fSAsmitha Karunanithi } 1108a43be80fSAsmitha Karunanithi 1109a43be80fSAsmitha Karunanithi if (dumpType == "System") 1110a43be80fSAsmitha Karunanithi { 1111a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 1112a43be80fSAsmitha Karunanithi { 111362598e31SEd Tanous BMCWEB_LOG_ERROR( 111462598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 1115a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1116a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 1117a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 1118a43be80fSAsmitha Karunanithi return; 1119a43be80fSAsmitha Karunanithi } 11203174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 1121a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 1122a43be80fSAsmitha Karunanithi { 112362598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 1124ace85d60SEd Tanous messages::internalError(asyncResp->res); 1125a43be80fSAsmitha Karunanithi return; 1126a43be80fSAsmitha Karunanithi } 1127*253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump/", 1128*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1129a43be80fSAsmitha Karunanithi } 1130a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 1131a43be80fSAsmitha Karunanithi { 1132a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 1133a43be80fSAsmitha Karunanithi { 113462598e31SEd Tanous BMCWEB_LOG_ERROR( 113562598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 1136a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1137a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 1138a43be80fSAsmitha Karunanithi return; 1139a43be80fSAsmitha Karunanithi } 11403174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 1141a43be80fSAsmitha Karunanithi { 114262598e31SEd Tanous BMCWEB_LOG_ERROR( 114362598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 1144ace85d60SEd Tanous messages::internalError(asyncResp->res); 1145a43be80fSAsmitha Karunanithi return; 1146a43be80fSAsmitha Karunanithi } 1147*253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump/", 1148*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 11495907571dSAsmitha Karunanithi } 11505907571dSAsmitha Karunanithi else 11515907571dSAsmitha Karunanithi { 115262598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 11535907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11545907571dSAsmitha Karunanithi return; 1155a43be80fSAsmitha Karunanithi } 1156a43be80fSAsmitha Karunanithi 11578e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 11588e31778eSAsmitha Karunanithi createDumpParamVec; 11598e31778eSAsmitha Karunanithi 1160f574a8e1SCarson Labrado if (req.session != nullptr) 1161f574a8e1SCarson Labrado { 116268dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 116368dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 116468dd075aSAsmitha Karunanithi req.session->clientIp); 116568dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 116668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 116768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1168f574a8e1SCarson Labrado } 116968dd075aSAsmitha Karunanithi 1170a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 11715e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 11725e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 11735e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 11748e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1175a43be80fSAsmitha Karunanithi if (ec) 1176a43be80fSAsmitha Karunanithi { 117762598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 11785907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 11795907571dSAsmitha Karunanithi if (dbusError == nullptr) 11805907571dSAsmitha Karunanithi { 11815907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11825907571dSAsmitha Karunanithi return; 11835907571dSAsmitha Karunanithi } 11845907571dSAsmitha Karunanithi 118562598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 118662598e31SEd Tanous dbusError->name, dbusError->message); 11875907571dSAsmitha Karunanithi if (std::string_view( 11885907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 11895907571dSAsmitha Karunanithi dbusError->name) 11905907571dSAsmitha Karunanithi { 11915907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 11925907571dSAsmitha Karunanithi return; 11935907571dSAsmitha Karunanithi } 11945907571dSAsmitha Karunanithi if (std::string_view( 11955907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 11965907571dSAsmitha Karunanithi dbusError->name) 11975907571dSAsmitha Karunanithi { 11985907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 11995907571dSAsmitha Karunanithi return; 12005907571dSAsmitha Karunanithi } 12015907571dSAsmitha Karunanithi if (std::string_view( 12025907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 12035907571dSAsmitha Karunanithi dbusError->name) 12045907571dSAsmitha Karunanithi { 12055907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 12065907571dSAsmitha Karunanithi return; 12075907571dSAsmitha Karunanithi } 12085907571dSAsmitha Karunanithi // Other Dbus errors such as: 12095907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 12105907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 12115907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 12125907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 12135907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 12145907571dSAsmitha Karunanithi // back to the client. 1215a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1216a43be80fSAsmitha Karunanithi return; 1217a43be80fSAsmitha Karunanithi } 121862598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 12198e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1220a43be80fSAsmitha Karunanithi }, 122118f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12228e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1223a43be80fSAsmitha Karunanithi } 1224a43be80fSAsmitha Karunanithi 12258d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12268d1b46d7Szhanghch05 const std::string& dumpType) 122780319af1SAsmitha Karunanithi { 12280d946211SClaire Weinan crow::connections::systemBus->async_method_call( 12290d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 123080319af1SAsmitha Karunanithi if (ec) 123180319af1SAsmitha Karunanithi { 123262598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 123380319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 123480319af1SAsmitha Karunanithi return; 123580319af1SAsmitha Karunanithi } 12360d946211SClaire Weinan }, 123718f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12380d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 123980319af1SAsmitha Karunanithi } 124080319af1SAsmitha Karunanithi 1241df254f2cSEd Tanous inline void 1242b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1243b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1244b9d36b47SEd Tanous std::string& logfile) 1245043a0536SJohnathan Mantey { 1246d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1247d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1248d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1249d1bde9e5SKrzysztof Grobelny 1250d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1251d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1252d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1253d1bde9e5SKrzysztof Grobelny 1254d1bde9e5SKrzysztof Grobelny if (!success) 1255043a0536SJohnathan Mantey { 1256d1bde9e5SKrzysztof Grobelny return; 1257043a0536SJohnathan Mantey } 1258d1bde9e5SKrzysztof Grobelny 1259d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1260043a0536SJohnathan Mantey { 1261d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1262d1bde9e5SKrzysztof Grobelny } 1263d1bde9e5SKrzysztof Grobelny 1264d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1265043a0536SJohnathan Mantey { 1266d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1267043a0536SJohnathan Mantey } 1268d1bde9e5SKrzysztof Grobelny 1269d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1270043a0536SJohnathan Mantey { 1271d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1272043a0536SJohnathan Mantey } 1273043a0536SJohnathan Mantey } 1274043a0536SJohnathan Mantey 12757e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 12761da66f75SEd Tanous { 1277c4bf6374SJason M. Bills /** 1278c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1279c4bf6374SJason M. Bills */ 128022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1281ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1282002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1283002d39b4SEd Tanous [&app](const crow::Request& req, 128422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 128522d268cbSEd Tanous const std::string& systemName) { 12863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1287c4bf6374SJason M. Bills { 128845ca1b86SEd Tanous return; 128945ca1b86SEd Tanous } 129025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 12917f3e84a1SEd Tanous { 12927f3e84a1SEd Tanous // Option currently returns no systems. TBD 12937f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 12947f3e84a1SEd Tanous systemName); 12957f3e84a1SEd Tanous return; 12967f3e84a1SEd Tanous } 1297*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 129822d268cbSEd Tanous { 129922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 130022d268cbSEd Tanous systemName); 130122d268cbSEd Tanous return; 130222d268cbSEd Tanous } 130322d268cbSEd Tanous 13047e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13057e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1306c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1307c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1308c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1309*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices", 1310*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 131145ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1312c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1313c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1314002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1315c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 13161476687dSEd Tanous nlohmann::json::object_t eventLog; 13171476687dSEd Tanous eventLog["@odata.id"] = 1318*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1319*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1320b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 132125b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 132225b54dbaSEd Tanous { 13231476687dSEd Tanous nlohmann::json::object_t dumpLog; 132425b54dbaSEd Tanous dumpLog["@odata.id"] = 1325*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Dump", 1326*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1327b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 132825b54dbaSEd Tanous } 1329c9bb6861Sraviteja-b 13305ffd11f2SGunnar Mills if constexpr (BMCWEB_REDFISH_CPU_LOG) 133125b54dbaSEd Tanous { 13321476687dSEd Tanous nlohmann::json::object_t crashdump; 13331476687dSEd Tanous crashdump["@odata.id"] = 1334*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 1335*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1336b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 133725b54dbaSEd Tanous } 1338b7028ebfSSpencer Ku 133925b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_HOST_LOGGER) 134025b54dbaSEd Tanous { 13411476687dSEd Tanous nlohmann::json::object_t hostlogger; 13421476687dSEd Tanous hostlogger["@odata.id"] = 1343*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 1344*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1345b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 134625b54dbaSEd Tanous } 1347c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1348c4bf6374SJason M. Bills logServiceArray.size(); 1349a3316fc6SZhikuiRen 13507a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 13517a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 13527a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 13537a1dbc48SGeorge Liu "/", 0, interfaces, 13547a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1355b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1356b9d36b47SEd Tanous subtreePath) { 1357a3316fc6SZhikuiRen if (ec) 1358a3316fc6SZhikuiRen { 135962598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1360a3316fc6SZhikuiRen return; 1361a3316fc6SZhikuiRen } 1362a3316fc6SZhikuiRen 136355f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1364a3316fc6SZhikuiRen { 1365a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1366a3316fc6SZhikuiRen { 136723a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1368a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1369613dabeaSEd Tanous nlohmann::json::object_t member; 1370*253f11b8SEd Tanous member["@odata.id"] = std::format( 1371*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes", 1372*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1373613dabeaSEd Tanous 1374b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1375613dabeaSEd Tanous 137645ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 137723a21a1cSEd Tanous logServiceArrayLocal.size(); 1378a3316fc6SZhikuiRen return; 1379a3316fc6SZhikuiRen } 1380a3316fc6SZhikuiRen } 13817a1dbc48SGeorge Liu }); 13827e860f15SJohn Edward Broadbent }); 1383c4bf6374SJason M. Bills } 1384c4bf6374SJason M. Bills 13857e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1386c4bf6374SJason M. Bills { 138722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1388ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1389002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1390002d39b4SEd Tanous [&app](const crow::Request& req, 139122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 139222d268cbSEd Tanous const std::string& systemName) { 13933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 139445ca1b86SEd Tanous { 139545ca1b86SEd Tanous return; 139645ca1b86SEd Tanous } 1397*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 139822d268cbSEd Tanous { 139922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 140022d268cbSEd Tanous systemName); 140122d268cbSEd Tanous return; 140222d268cbSEd Tanous } 1403c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1404*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog", 1405*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1406c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1407b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1408c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1409002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1410c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1411c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 14127c8c4058STejas Patil 14137c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 14142b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 14157c8c4058STejas Patil 14167c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 14177c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 14187c8c4058STejas Patil redfishDateTimeOffset.second; 14197c8c4058STejas Patil 14201476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 1421*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1422*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1423e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1424e7d6c8b2SGunnar Mills 14250fda0f12SGeorge Liu {"target", 1426*253f11b8SEd Tanous std::format( 1427*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog", 1428*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME)}}; 14297e860f15SJohn Edward Broadbent }); 1430489640c6SJason M. Bills } 1431489640c6SJason M. Bills 14327e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1433489640c6SJason M. Bills { 14344978b63fSJason M. Bills BMCWEB_ROUTE( 14354978b63fSJason M. Bills app, 143622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1437432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 14387e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 143945ca1b86SEd Tanous [&app](const crow::Request& req, 144022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 144122d268cbSEd Tanous const std::string& systemName) { 14423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 144345ca1b86SEd Tanous { 144445ca1b86SEd Tanous return; 144545ca1b86SEd Tanous } 1446*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 144722d268cbSEd Tanous { 144822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 144922d268cbSEd Tanous systemName); 145022d268cbSEd Tanous return; 145122d268cbSEd Tanous } 1452489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1453489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1454489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1455489640c6SJason M. Bills { 1456489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1457489640c6SJason M. Bills { 1458489640c6SJason M. Bills std::error_code ec; 1459489640c6SJason M. Bills std::filesystem::remove(file, ec); 1460489640c6SJason M. Bills } 1461489640c6SJason M. Bills } 1462489640c6SJason M. Bills 1463489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1464489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 14655e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1466489640c6SJason M. Bills if (ec) 1467489640c6SJason M. Bills { 146862598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1469489640c6SJason M. Bills messages::internalError(asyncResp->res); 1470489640c6SJason M. Bills return; 1471489640c6SJason M. Bills } 1472489640c6SJason M. Bills 1473489640c6SJason M. Bills messages::success(asyncResp->res); 1474489640c6SJason M. Bills }, 1475489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1476002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1477002d39b4SEd Tanous "replace"); 14787e860f15SJohn Edward Broadbent }); 1479c4bf6374SJason M. Bills } 1480c4bf6374SJason M. Bills 1481ac992cdeSJason M. Bills enum class LogParseError 1482ac992cdeSJason M. Bills { 1483ac992cdeSJason M. Bills success, 1484ac992cdeSJason M. Bills parseFailed, 1485ac992cdeSJason M. Bills messageIdNotInRegistry, 1486ac992cdeSJason M. Bills }; 1487ac992cdeSJason M. Bills 1488ac992cdeSJason M. Bills static LogParseError 1489ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1490b5a76932SEd Tanous const std::string& logEntry, 1491de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1492c4bf6374SJason M. Bills { 149395820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1494cd225da8SJason M. Bills // First get the Timestamp 1495f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1496cd225da8SJason M. Bills if (space == std::string::npos) 149795820184SJason M. Bills { 1498ac992cdeSJason M. Bills return LogParseError::parseFailed; 149995820184SJason M. Bills } 1500cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1501cd225da8SJason M. Bills // Then get the log contents 1502f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1503cd225da8SJason M. Bills if (entryStart == std::string::npos) 1504cd225da8SJason M. Bills { 1505ac992cdeSJason M. Bills return LogParseError::parseFailed; 1506cd225da8SJason M. Bills } 1507cd225da8SJason M. Bills std::string_view entry(logEntry); 1508cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1509cd225da8SJason M. Bills // Use split to separate the entry into its fields 1510cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 151150ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1512cd225da8SJason M. Bills // We need at least a MessageId to be valid 15131e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 15141e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1515cd225da8SJason M. Bills { 1516ac992cdeSJason M. Bills return LogParseError::parseFailed; 1517cd225da8SJason M. Bills } 15181e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 15194851d45dSJason M. Bills // Get the Message from the MessageRegistry 1520fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1521c4bf6374SJason M. Bills 15221e6deaf6SEd Tanous logEntryIter++; 152354417b02SSui Chen if (message == nullptr) 1524c4bf6374SJason M. Bills { 152562598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1526ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1527c4bf6374SJason M. Bills } 1528c4bf6374SJason M. Bills 15291e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 15301e6deaf6SEd Tanous logEntryFields.end()); 1531c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1532c05bba45SEd Tanous 15331e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 15341e6deaf6SEd Tanous message->message); 15351e6deaf6SEd Tanous if (msg.empty()) 153615a86ff6SJason M. Bills { 15371e6deaf6SEd Tanous return LogParseError::parseFailed; 153815a86ff6SJason M. Bills } 15394851d45dSJason M. Bills 154095820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 154195820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 154295820184SJason M. Bills // between the '.' and the '+', so just remove them. 1543f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1544f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 154595820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1546c4bf6374SJason M. Bills { 154795820184SJason M. Bills timestamp.erase(dot, plus - dot); 1548c4bf6374SJason M. Bills } 1549c4bf6374SJason M. Bills 1550c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 15519c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1552ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1553*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1554*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 155584afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 155684afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 155784afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 155884afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 155984afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 156084afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 156184afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 156284afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1563ac992cdeSJason M. Bills return LogParseError::success; 1564c4bf6374SJason M. Bills } 1565c4bf6374SJason M. Bills 15667e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1567c4bf6374SJason M. Bills { 156822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 15698b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1570002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1571002d39b4SEd Tanous [&app](const crow::Request& req, 157222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 157322d268cbSEd Tanous const std::string& systemName) { 1574c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1575c937d2bfSEd Tanous .canDelegateTop = true, 1576c937d2bfSEd Tanous .canDelegateSkip = true, 1577c937d2bfSEd Tanous }; 1578c937d2bfSEd Tanous query_param::Query delegatedQuery; 1579c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 15803ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1581c4bf6374SJason M. Bills { 1582c4bf6374SJason M. Bills return; 1583c4bf6374SJason M. Bills } 158425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 15857f3e84a1SEd Tanous { 15867f3e84a1SEd Tanous // Option currently returns no systems. TBD 15877f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15887f3e84a1SEd Tanous systemName); 15897f3e84a1SEd Tanous return; 15907f3e84a1SEd Tanous } 1591*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 159222d268cbSEd Tanous { 159322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 159422d268cbSEd Tanous systemName); 159522d268cbSEd Tanous return; 159622d268cbSEd Tanous } 159722d268cbSEd Tanous 15985143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15993648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 16003648c8beSEd Tanous 16017e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 16027e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1603c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1604c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1605c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1606*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1607*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 1608c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1609c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1610c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1611cb92c03bSAndrew Geissler 16124978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1613c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 16147e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 16157e860f15SJohn Edward Broadbent // entry 161695820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 161795820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1618b01bf299SEd Tanous uint64_t entryCount = 0; 1619cd225da8SJason M. Bills std::string logEntry; 162095820184SJason M. Bills 16217e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16227e860f15SJohn Edward Broadbent // backwards 1623002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1624002d39b4SEd Tanous it++) 1625c4bf6374SJason M. Bills { 1626cd225da8SJason M. Bills std::ifstream logStream(*it); 162795820184SJason M. Bills if (!logStream.is_open()) 1628c4bf6374SJason M. Bills { 1629c4bf6374SJason M. Bills continue; 1630c4bf6374SJason M. Bills } 1631c4bf6374SJason M. Bills 1632e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1633e85d6b16SJason M. Bills bool firstEntry = true; 163495820184SJason M. Bills while (std::getline(logStream, logEntry)) 163595820184SJason M. Bills { 1636c4bf6374SJason M. Bills std::string idStr; 1637e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1638c4bf6374SJason M. Bills { 1639c4bf6374SJason M. Bills continue; 1640c4bf6374SJason M. Bills } 1641e85d6b16SJason M. Bills firstEntry = false; 1642e85d6b16SJason M. Bills 1643de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 164489492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 164589492a15SPatrick Williams bmcLogEntry); 1646ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1647ac992cdeSJason M. Bills { 1648ac992cdeSJason M. Bills continue; 1649ac992cdeSJason M. Bills } 1650ac992cdeSJason M. Bills if (status != LogParseError::success) 1651c4bf6374SJason M. Bills { 1652c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1653c4bf6374SJason M. Bills return; 1654c4bf6374SJason M. Bills } 1655de703c5dSJason M. Bills 1656de703c5dSJason M. Bills entryCount++; 1657de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1658de703c5dSJason M. Bills // start) and top (number of entries to display) 16593648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1660de703c5dSJason M. Bills { 1661de703c5dSJason M. Bills continue; 1662de703c5dSJason M. Bills } 1663de703c5dSJason M. Bills 1664b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1665c4bf6374SJason M. Bills } 166695820184SJason M. Bills } 1667c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16683648c8beSEd Tanous if (skip + top < entryCount) 1669c4bf6374SJason M. Bills { 1670*253f11b8SEd Tanous asyncResp->res 1671*253f11b8SEd Tanous .jsonValue["Members@odata.nextLink"] = boost::urls::format( 1672*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}", 1673*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top)); 1674c4bf6374SJason M. Bills } 16757e860f15SJohn Edward Broadbent }); 1676897967deSJason M. Bills } 1677897967deSJason M. Bills 16787e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1679897967deSJason M. Bills { 16807e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 168122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1682ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 16837e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 168445ca1b86SEd Tanous [&app](const crow::Request& req, 16857e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 168622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16873ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 168845ca1b86SEd Tanous { 168945ca1b86SEd Tanous return; 169045ca1b86SEd Tanous } 169125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 16927f3e84a1SEd Tanous { 16937f3e84a1SEd Tanous // Option currently returns no systems. TBD 16947f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16957f3e84a1SEd Tanous systemName); 16967f3e84a1SEd Tanous return; 16977f3e84a1SEd Tanous } 169822d268cbSEd Tanous 1699*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 170022d268cbSEd Tanous { 170122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 170222d268cbSEd Tanous systemName); 170322d268cbSEd Tanous return; 170422d268cbSEd Tanous } 170522d268cbSEd Tanous 17067e860f15SJohn Edward Broadbent const std::string& targetID = param; 17078d1b46d7Szhanghch05 17087e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 17097e860f15SJohn Edward Broadbent // entry to find the target entry 1710897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1711897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1712897967deSJason M. Bills std::string logEntry; 1713897967deSJason M. Bills 17147e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 17157e860f15SJohn Edward Broadbent // backwards 1716002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1717002d39b4SEd Tanous it++) 1718897967deSJason M. Bills { 1719897967deSJason M. Bills std::ifstream logStream(*it); 1720897967deSJason M. Bills if (!logStream.is_open()) 1721897967deSJason M. Bills { 1722897967deSJason M. Bills continue; 1723897967deSJason M. Bills } 1724897967deSJason M. Bills 1725897967deSJason M. Bills // Reset the unique ID on the first entry 1726897967deSJason M. Bills bool firstEntry = true; 1727897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1728897967deSJason M. Bills { 1729897967deSJason M. Bills std::string idStr; 1730897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1731897967deSJason M. Bills { 1732897967deSJason M. Bills continue; 1733897967deSJason M. Bills } 1734897967deSJason M. Bills firstEntry = false; 1735897967deSJason M. Bills 1736897967deSJason M. Bills if (idStr == targetID) 1737897967deSJason M. Bills { 1738de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1739ac992cdeSJason M. Bills LogParseError status = 1740ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1741ac992cdeSJason M. Bills if (status != LogParseError::success) 1742897967deSJason M. Bills { 1743897967deSJason M. Bills messages::internalError(asyncResp->res); 1744897967deSJason M. Bills return; 1745897967deSJason M. Bills } 1746d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1747897967deSJason M. Bills return; 1748897967deSJason M. Bills } 1749897967deSJason M. Bills } 1750897967deSJason M. Bills } 1751897967deSJason M. Bills // Requested ID was not found 17529db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 17537e860f15SJohn Edward Broadbent }); 175408a4e4b5SAnthony Wilson } 175508a4e4b5SAnthony Wilson 17567e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 175708a4e4b5SAnthony Wilson { 175822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1759ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1760002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1761002d39b4SEd Tanous [&app](const crow::Request& req, 176222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 176322d268cbSEd Tanous const std::string& systemName) { 17643ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 176545ca1b86SEd Tanous { 176645ca1b86SEd Tanous return; 176745ca1b86SEd Tanous } 176825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 17697f3e84a1SEd Tanous { 17707f3e84a1SEd Tanous // Option currently returns no systems. TBD 17717f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17727f3e84a1SEd Tanous systemName); 17737f3e84a1SEd Tanous return; 17747f3e84a1SEd Tanous } 1775*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 177622d268cbSEd Tanous { 177722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 177822d268cbSEd Tanous systemName); 177922d268cbSEd Tanous return; 178022d268cbSEd Tanous } 178122d268cbSEd Tanous 17827e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 17837e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 178408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 178508a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 178608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 1787*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries", 1788*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 178908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 179008a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 179108a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 179208a4e4b5SAnthony Wilson 1793cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1794cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 17955eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 17965eb468daSGeorge Liu dbus::utility::getManagedObjects( 17975eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 17985e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1799914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1800cb92c03bSAndrew Geissler if (ec) 1801cb92c03bSAndrew Geissler { 1802cb92c03bSAndrew Geissler // TODO Handle for specific error code 180362598e31SEd Tanous BMCWEB_LOG_ERROR( 180462598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1805cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1806cb92c03bSAndrew Geissler return; 1807cb92c03bSAndrew Geissler } 18083544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 18099eb808c1SEd Tanous for (const auto& objectPath : resp) 1810cb92c03bSAndrew Geissler { 1811914e2d5dSEd Tanous const uint32_t* id = nullptr; 1812c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1813c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1814914e2d5dSEd Tanous const std::string* severity = nullptr; 1815914e2d5dSEd Tanous const std::string* message = nullptr; 1816914e2d5dSEd Tanous const std::string* filePath = nullptr; 18179c11a172SVijay Lobo const std::string* resolution = nullptr; 181875710de2SXiaochao Ma bool resolved = false; 18199017faf2SAbhishek Patel const std::string* notify = nullptr; 18209017faf2SAbhishek Patel 18219eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1822f86bb901SAdriana Kobylak { 1823f86bb901SAdriana Kobylak if (interfaceMap.first == 1824f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1825f86bb901SAdriana Kobylak { 1826002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1827cb92c03bSAndrew Geissler { 1828cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1829cb92c03bSAndrew Geissler { 1830002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1831cb92c03bSAndrew Geissler } 1832cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1833cb92c03bSAndrew Geissler { 1834002d39b4SEd Tanous timestamp = 1835002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18367e860f15SJohn Edward Broadbent } 1837002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 18387e860f15SJohn Edward Broadbent { 1839002d39b4SEd Tanous updateTimestamp = 1840002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18417e860f15SJohn Edward Broadbent } 18427e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 18437e860f15SJohn Edward Broadbent { 18447e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 18457e860f15SJohn Edward Broadbent &propertyMap.second); 18467e860f15SJohn Edward Broadbent } 18479c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 18489c11a172SVijay Lobo { 18499c11a172SVijay Lobo resolution = std::get_if<std::string>( 18509c11a172SVijay Lobo &propertyMap.second); 18519c11a172SVijay Lobo } 18527e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 18537e860f15SJohn Edward Broadbent { 18547e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 18557e860f15SJohn Edward Broadbent &propertyMap.second); 18567e860f15SJohn Edward Broadbent } 18577e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 18587e860f15SJohn Edward Broadbent { 1859914e2d5dSEd Tanous const bool* resolveptr = 1860002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 18617e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 18627e860f15SJohn Edward Broadbent { 1863002d39b4SEd Tanous messages::internalError(asyncResp->res); 18647e860f15SJohn Edward Broadbent return; 18657e860f15SJohn Edward Broadbent } 18667e860f15SJohn Edward Broadbent resolved = *resolveptr; 18677e860f15SJohn Edward Broadbent } 18689017faf2SAbhishek Patel else if (propertyMap.first == 18699017faf2SAbhishek Patel "ServiceProviderNotify") 18709017faf2SAbhishek Patel { 18719017faf2SAbhishek Patel notify = std::get_if<std::string>( 18729017faf2SAbhishek Patel &propertyMap.second); 18739017faf2SAbhishek Patel if (notify == nullptr) 18749017faf2SAbhishek Patel { 18759017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18769017faf2SAbhishek Patel return; 18779017faf2SAbhishek Patel } 18789017faf2SAbhishek Patel } 18797e860f15SJohn Edward Broadbent } 18807e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 18817e860f15SJohn Edward Broadbent severity == nullptr) 18827e860f15SJohn Edward Broadbent { 18837e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18847e860f15SJohn Edward Broadbent return; 18857e860f15SJohn Edward Broadbent } 18867e860f15SJohn Edward Broadbent } 18877e860f15SJohn Edward Broadbent else if (interfaceMap.first == 18887e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 18897e860f15SJohn Edward Broadbent { 1890002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 18917e860f15SJohn Edward Broadbent { 18927e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 18937e860f15SJohn Edward Broadbent { 18947e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 18957e860f15SJohn Edward Broadbent &propertyMap.second); 18967e860f15SJohn Edward Broadbent } 18977e860f15SJohn Edward Broadbent } 18987e860f15SJohn Edward Broadbent } 18997e860f15SJohn Edward Broadbent } 19007e860f15SJohn Edward Broadbent // Object path without the 19017e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 19027e860f15SJohn Edward Broadbent // and continue. 19037e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1904c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1905c419c759SEd Tanous updateTimestamp == nullptr) 19067e860f15SJohn Edward Broadbent { 19077e860f15SJohn Edward Broadbent continue; 19087e860f15SJohn Edward Broadbent } 19093544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 19109c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1911ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1912*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 1913*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 19147e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 19157e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 19167e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 19177e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 19189c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 19199c11a172SVijay Lobo { 19209c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 19219c11a172SVijay Lobo } 19229017faf2SAbhishek Patel std::optional<bool> notifyAction = 19239017faf2SAbhishek Patel getProviderNotifyAction(*notify); 19249017faf2SAbhishek Patel if (notifyAction) 19259017faf2SAbhishek Patel { 19269017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 19279017faf2SAbhishek Patel } 19287e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 19297e860f15SJohn Edward Broadbent thisEntry["Severity"] = 19307e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 19317e860f15SJohn Edward Broadbent thisEntry["Created"] = 19322b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 19337e860f15SJohn Edward Broadbent thisEntry["Modified"] = 19342b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 19357e860f15SJohn Edward Broadbent if (filePath != nullptr) 19367e860f15SJohn Edward Broadbent { 19377e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 1938*253f11b8SEd Tanous std::format( 1939*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 1940*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 19417e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 19427e860f15SJohn Edward Broadbent } 19437e860f15SJohn Edward Broadbent } 19443544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 19453544d2a7SEd Tanous const nlohmann::json& right) { 19467e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 19477e860f15SJohn Edward Broadbent }); 19487e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 19497e860f15SJohn Edward Broadbent entriesArray.size(); 19503544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 19515eb468daSGeorge Liu }); 19527e860f15SJohn Edward Broadbent }); 19537e860f15SJohn Edward Broadbent } 19547e860f15SJohn Edward Broadbent 19557e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 19567e860f15SJohn Edward Broadbent { 19577e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 195822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1959ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1960002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1961002d39b4SEd Tanous [&app](const crow::Request& req, 19627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 196322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19643ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19657e860f15SJohn Edward Broadbent { 196645ca1b86SEd Tanous return; 196745ca1b86SEd Tanous } 196825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 19697f3e84a1SEd Tanous { 19707f3e84a1SEd Tanous // Option currently returns no systems. TBD 19717f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19727f3e84a1SEd Tanous systemName); 19737f3e84a1SEd Tanous return; 19747f3e84a1SEd Tanous } 1975*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 197622d268cbSEd Tanous { 197722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 197822d268cbSEd Tanous systemName); 197922d268cbSEd Tanous return; 198022d268cbSEd Tanous } 198122d268cbSEd Tanous 19827e860f15SJohn Edward Broadbent std::string entryID = param; 19837e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 19847e860f15SJohn Edward Broadbent 19857e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 19867e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1987d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1988d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1989d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 19905e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1991b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 19927e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 19937e860f15SJohn Edward Broadbent { 1994d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1995d1bde9e5SKrzysztof Grobelny entryID); 19967e860f15SJohn Edward Broadbent return; 19977e860f15SJohn Edward Broadbent } 19987e860f15SJohn Edward Broadbent if (ec) 19997e860f15SJohn Edward Broadbent { 200062598e31SEd Tanous BMCWEB_LOG_ERROR( 200162598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 20027e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 20037e860f15SJohn Edward Broadbent return; 20047e860f15SJohn Edward Broadbent } 2005914e2d5dSEd Tanous const uint32_t* id = nullptr; 2006c419c759SEd Tanous const uint64_t* timestamp = nullptr; 2007c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 2008914e2d5dSEd Tanous const std::string* severity = nullptr; 2009914e2d5dSEd Tanous const std::string* message = nullptr; 2010914e2d5dSEd Tanous const std::string* filePath = nullptr; 20119c11a172SVijay Lobo const std::string* resolution = nullptr; 20127e860f15SJohn Edward Broadbent bool resolved = false; 20139017faf2SAbhishek Patel const std::string* notify = nullptr; 20147e860f15SJohn Edward Broadbent 2015d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 2016d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 2017d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 20189c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 20199017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 20209017faf2SAbhishek Patel "ServiceProviderNotify", notify); 2021d1bde9e5SKrzysztof Grobelny 2022d1bde9e5SKrzysztof Grobelny if (!success) 202375710de2SXiaochao Ma { 202475710de2SXiaochao Ma messages::internalError(asyncResp->res); 202575710de2SXiaochao Ma return; 202675710de2SXiaochao Ma } 2027d1bde9e5SKrzysztof Grobelny 2028002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 20299017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 20309017faf2SAbhishek Patel notify == nullptr) 2031f86bb901SAdriana Kobylak { 2032ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 2033271584abSEd Tanous return; 2034271584abSEd Tanous } 20359017faf2SAbhishek Patel 2036f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 20379c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 2038ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2039*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}", 2040*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id)); 204145ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 2042f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 2043f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 2044f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 20459017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 20469017faf2SAbhishek Patel if (notifyAction) 20479017faf2SAbhishek Patel { 20489017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 20499017faf2SAbhishek Patel *notifyAction; 20509017faf2SAbhishek Patel } 20519c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 20529c11a172SVijay Lobo { 20539c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 20549c11a172SVijay Lobo } 2055f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 2056f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 2057f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 2058f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 20592b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 2060f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 20612b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 2062f86bb901SAdriana Kobylak if (filePath != nullptr) 2063f86bb901SAdriana Kobylak { 2064f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 2065*253f11b8SEd Tanous std::format( 2066*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/", 2067*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 2068e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 2069f86bb901SAdriana Kobylak } 2070d1bde9e5SKrzysztof Grobelny }); 20717e860f15SJohn Edward Broadbent }); 2072336e96c6SChicago Duan 20737e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 207422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2075ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 20767e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 207745ca1b86SEd Tanous [&app](const crow::Request& req, 20787e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 207922d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 20803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 208145ca1b86SEd Tanous { 208245ca1b86SEd Tanous return; 208345ca1b86SEd Tanous } 208425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20857f3e84a1SEd Tanous { 20867f3e84a1SEd Tanous // Option currently returns no systems. TBD 20877f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20887f3e84a1SEd Tanous systemName); 20897f3e84a1SEd Tanous return; 20907f3e84a1SEd Tanous } 2091*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 209222d268cbSEd Tanous { 209322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 209422d268cbSEd Tanous systemName); 209522d268cbSEd Tanous return; 209622d268cbSEd Tanous } 209775710de2SXiaochao Ma std::optional<bool> resolved; 209875710de2SXiaochao Ma 209915ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 21007e860f15SJohn Edward Broadbent resolved)) 210175710de2SXiaochao Ma { 210275710de2SXiaochao Ma return; 210375710de2SXiaochao Ma } 210462598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 210575710de2SXiaochao Ma 21063eb66652SAsmitha Karunanithi setDbusProperty(asyncResp, "xyz.openbmc_project.Logging", 21079ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 21083eb66652SAsmitha Karunanithi "xyz.openbmc_project.Logging.Entry", "Resolved", 21093eb66652SAsmitha Karunanithi "Resolved", *resolved); 21107e860f15SJohn Edward Broadbent }); 211175710de2SXiaochao Ma 21127e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 211322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2114ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2115ed398213SEd Tanous 2116002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2117002d39b4SEd Tanous [&app](const crow::Request& req, 2118002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 211922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2121336e96c6SChicago Duan { 212245ca1b86SEd Tanous return; 212345ca1b86SEd Tanous } 212425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 21257f3e84a1SEd Tanous { 21267f3e84a1SEd Tanous // Option currently returns no systems. TBD 21277f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21287f3e84a1SEd Tanous systemName); 21297f3e84a1SEd Tanous return; 21307f3e84a1SEd Tanous } 2131*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 213222d268cbSEd Tanous { 213322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 213422d268cbSEd Tanous systemName); 213522d268cbSEd Tanous return; 213622d268cbSEd Tanous } 213762598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 2138336e96c6SChicago Duan 21397e860f15SJohn Edward Broadbent std::string entryID = param; 2140336e96c6SChicago Duan 2141336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 2142336e96c6SChicago Duan 2143336e96c6SChicago Duan // Process response from Logging service. 21445a39f77aSPatrick Williams auto respHandler = [asyncResp, 21455a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 214662598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 2147336e96c6SChicago Duan if (ec) 2148336e96c6SChicago Duan { 21493de8d8baSGeorge Liu if (ec.value() == EBADR) 21503de8d8baSGeorge Liu { 215145ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 215245ca1b86SEd Tanous entryID); 21533de8d8baSGeorge Liu return; 21543de8d8baSGeorge Liu } 2155336e96c6SChicago Duan // TODO Handle for specific error code 215662598e31SEd Tanous BMCWEB_LOG_ERROR( 215762598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 215862598e31SEd Tanous ec); 2159336e96c6SChicago Duan asyncResp->res.result( 2160336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 2161336e96c6SChicago Duan return; 2162336e96c6SChicago Duan } 2163336e96c6SChicago Duan 2164336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 2165336e96c6SChicago Duan }; 2166336e96c6SChicago Duan 2167336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2168336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2169336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2170336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2171336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 21727e860f15SJohn Edward Broadbent }); 2173400fd1fbSAdriana Kobylak } 2174400fd1fbSAdriana Kobylak 2175b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2176b7028ebfSSpencer Ku 2177b7028ebfSSpencer Ku inline bool 2178b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2179b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2180b7028ebfSSpencer Ku { 2181b7028ebfSSpencer Ku std::error_code ec; 2182b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2183b7028ebfSSpencer Ku if (ec) 2184b7028ebfSSpencer Ku { 2185bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2186b7028ebfSSpencer Ku return false; 2187b7028ebfSSpencer Ku } 2188b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2189b7028ebfSSpencer Ku { 2190b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2191b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2192b7028ebfSSpencer Ku // path 219311ba3979SEd Tanous if (filename.starts_with("log")) 2194b7028ebfSSpencer Ku { 2195b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2196b7028ebfSSpencer Ku } 2197b7028ebfSSpencer Ku } 2198b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2199b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2200b7028ebfSSpencer Ku // descending order. 2201b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2202b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2203b7028ebfSSpencer Ku 2204b7028ebfSSpencer Ku return true; 2205b7028ebfSSpencer Ku } 2206b7028ebfSSpencer Ku 220702cad96eSEd Tanous inline bool getHostLoggerEntries( 220802cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 220902cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2210b7028ebfSSpencer Ku { 2211b7028ebfSSpencer Ku GzFileReader logFile; 2212b7028ebfSSpencer Ku 2213b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2214b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2215b7028ebfSSpencer Ku { 2216b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2217b7028ebfSSpencer Ku { 221862598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2219b7028ebfSSpencer Ku return false; 2220b7028ebfSSpencer Ku } 2221b7028ebfSSpencer Ku } 2222b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2223b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2224b7028ebfSSpencer Ku if (!lastMessage.empty()) 2225b7028ebfSSpencer Ku { 2226b7028ebfSSpencer Ku logCount++; 2227b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2228b7028ebfSSpencer Ku { 2229b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2230b7028ebfSSpencer Ku } 2231b7028ebfSSpencer Ku } 2232b7028ebfSSpencer Ku return true; 2233b7028ebfSSpencer Ku } 2234b7028ebfSSpencer Ku 22356f056f24SEd Tanous inline void fillHostLoggerEntryJson(std::string_view logEntryID, 22366f056f24SEd Tanous std::string_view msg, 22376d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2238b7028ebfSSpencer Ku { 2239b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 22409c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2241ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2242*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}", 2243*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID); 22446d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 22456d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 22466d6574c9SJason M. Bills logEntryJson["Message"] = msg; 22476d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 22486d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 22496d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2250b7028ebfSSpencer Ku } 2251b7028ebfSSpencer Ku 2252b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2253b7028ebfSSpencer Ku { 225422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2255b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 22561476687dSEd Tanous .methods(boost::beast::http::verb::get)( 22571476687dSEd Tanous [&app](const crow::Request& req, 225822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 225922d268cbSEd Tanous const std::string& systemName) { 22603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 226145ca1b86SEd Tanous { 226245ca1b86SEd Tanous return; 226345ca1b86SEd Tanous } 226425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 22657f3e84a1SEd Tanous { 22667f3e84a1SEd Tanous // Option currently returns no systems. TBD 22677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22687f3e84a1SEd Tanous systemName); 22697f3e84a1SEd Tanous return; 22707f3e84a1SEd Tanous } 2271*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 227222d268cbSEd Tanous { 227322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 227422d268cbSEd Tanous systemName); 227522d268cbSEd Tanous return; 227622d268cbSEd Tanous } 2277b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2278*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger", 2279*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2280b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2281b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2282b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2283b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2284b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 22851476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 2286*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2287*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2288b7028ebfSSpencer Ku }); 2289b7028ebfSSpencer Ku } 2290b7028ebfSSpencer Ku 2291b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2292b7028ebfSSpencer Ku { 2293b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 229422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2295b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2296002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2297002d39b4SEd Tanous [&app](const crow::Request& req, 229822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 229922d268cbSEd Tanous const std::string& systemName) { 2300c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2301c937d2bfSEd Tanous .canDelegateTop = true, 2302c937d2bfSEd Tanous .canDelegateSkip = true, 2303c937d2bfSEd Tanous }; 2304c937d2bfSEd Tanous query_param::Query delegatedQuery; 2305c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 23063ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2307b7028ebfSSpencer Ku { 2308b7028ebfSSpencer Ku return; 2309b7028ebfSSpencer Ku } 231025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 23117f3e84a1SEd Tanous { 23127f3e84a1SEd Tanous // Option currently returns no systems. TBD 23137f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 23147f3e84a1SEd Tanous systemName); 23157f3e84a1SEd Tanous return; 23167f3e84a1SEd Tanous } 2317*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 231822d268cbSEd Tanous { 231922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 232022d268cbSEd Tanous systemName); 232122d268cbSEd Tanous return; 232222d268cbSEd Tanous } 2323b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2324*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries", 2325*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2326b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2327b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2328b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2329b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2330b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 23310fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2332b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2333b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2334b7028ebfSSpencer Ku 2335b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2336b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2337b7028ebfSSpencer Ku { 2338bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2339b7028ebfSSpencer Ku return; 2340b7028ebfSSpencer Ku } 23413648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 23423648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 23435143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2344b7028ebfSSpencer Ku size_t logCount = 0; 2345b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2346b7028ebfSSpencer Ku // control by skip and top. 2347b7028ebfSSpencer Ku std::vector<std::string> logEntries; 23483648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 23493648c8beSEd Tanous logCount)) 2350b7028ebfSSpencer Ku { 2351b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2352b7028ebfSSpencer Ku return; 2353b7028ebfSSpencer Ku } 2354b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2355b7028ebfSSpencer Ku // log count 235626f6976fSEd Tanous if (logEntries.empty()) 2357b7028ebfSSpencer Ku { 2358b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2359b7028ebfSSpencer Ku return; 2360b7028ebfSSpencer Ku } 236126f6976fSEd Tanous if (!logEntries.empty()) 2362b7028ebfSSpencer Ku { 2363b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2364b7028ebfSSpencer Ku { 23656d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23663648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 23673648c8beSEd Tanous hostLogEntry); 2368b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2369b7028ebfSSpencer Ku } 2370b7028ebfSSpencer Ku 2371b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 23723648c8beSEd Tanous if (skip + top < logCount) 2373b7028ebfSSpencer Ku { 2374b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 2375*253f11b8SEd Tanous std::format( 2376*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=", 2377*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 23783648c8beSEd Tanous std::to_string(skip + top); 2379b7028ebfSSpencer Ku } 2380b7028ebfSSpencer Ku } 2381b7028ebfSSpencer Ku }); 2382b7028ebfSSpencer Ku } 2383b7028ebfSSpencer Ku 2384b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2385b7028ebfSSpencer Ku { 2386b7028ebfSSpencer Ku BMCWEB_ROUTE( 238722d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2388b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2389b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 239045ca1b86SEd Tanous [&app](const crow::Request& req, 2391b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 239222d268cbSEd Tanous const std::string& systemName, const std::string& param) { 23933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 239445ca1b86SEd Tanous { 239545ca1b86SEd Tanous return; 239645ca1b86SEd Tanous } 239725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 23987f3e84a1SEd Tanous { 23997f3e84a1SEd Tanous // Option currently returns no systems. TBD 24007f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 24017f3e84a1SEd Tanous systemName); 24027f3e84a1SEd Tanous return; 24037f3e84a1SEd Tanous } 2404*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 240522d268cbSEd Tanous { 240622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 240722d268cbSEd Tanous systemName); 240822d268cbSEd Tanous return; 240922d268cbSEd Tanous } 24106f056f24SEd Tanous std::string_view targetID = param; 2411b7028ebfSSpencer Ku 2412b7028ebfSSpencer Ku uint64_t idInt = 0; 2413ca45aa3cSEd Tanous 24146f056f24SEd Tanous auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(), 241584396af9SPatrick Williams idInt); 24166f056f24SEd Tanous if (ec != std::errc{} || ptr != targetID.end()) 2417b7028ebfSSpencer Ku { 24189db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2419b7028ebfSSpencer Ku return; 2420b7028ebfSSpencer Ku } 2421b7028ebfSSpencer Ku 2422b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2423b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2424b7028ebfSSpencer Ku { 2425bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2426b7028ebfSSpencer Ku return; 2427b7028ebfSSpencer Ku } 2428b7028ebfSSpencer Ku 2429b7028ebfSSpencer Ku size_t logCount = 0; 24303648c8beSEd Tanous size_t top = 1; 2431b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2432b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2433b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2434b7028ebfSSpencer Ku // get that entry 2435002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2436002d39b4SEd Tanous logCount)) 2437b7028ebfSSpencer Ku { 2438b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2439b7028ebfSSpencer Ku return; 2440b7028ebfSSpencer Ku } 2441b7028ebfSSpencer Ku 2442b7028ebfSSpencer Ku if (!logEntries.empty()) 2443b7028ebfSSpencer Ku { 24446d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 24456d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 24466d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2447b7028ebfSSpencer Ku return; 2448b7028ebfSSpencer Ku } 2449b7028ebfSSpencer Ku 2450b7028ebfSSpencer Ku // Requested ID was not found 24519db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2452b7028ebfSSpencer Ku }); 2453b7028ebfSSpencer Ku } 2454b7028ebfSSpencer Ku 2455dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2456fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2457*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2458*253f11b8SEd Tanous const std::string& managerId) 24591da66f75SEd Tanous { 24603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 246145ca1b86SEd Tanous { 246245ca1b86SEd Tanous return; 246345ca1b86SEd Tanous } 2464*253f11b8SEd Tanous 2465*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2466*253f11b8SEd Tanous { 2467*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2468*253f11b8SEd Tanous return; 2469*253f11b8SEd Tanous } 2470*253f11b8SEd Tanous 24717e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24727e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2473e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 24741da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2475*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2476*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME); 2477002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2478e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 24791da66f75SEd Tanous "Collection of LogServices for this Manager"; 2480002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2481c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2482fdd26906SClaire Weinan 248325b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_BMC_JOURNAL) 248425b54dbaSEd Tanous { 2485613dabeaSEd Tanous nlohmann::json::object_t journal; 2486*253f11b8SEd Tanous journal["@odata.id"] = 2487*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal", 2488*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2489b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 249025b54dbaSEd Tanous } 2491fdd26906SClaire Weinan 2492fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2493fdd26906SClaire Weinan 249425b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_DUMP_LOG) 249525b54dbaSEd Tanous { 249615912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24977a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 24987a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 24997a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 250025b54dbaSEd Tanous [asyncResp](const boost::system::error_code& ec, 250125b54dbaSEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 250225b54dbaSEd Tanous subTreePaths) { 2503fdd26906SClaire Weinan if (ec) 2504fdd26906SClaire Weinan { 250562598e31SEd Tanous BMCWEB_LOG_ERROR( 250662598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 250762598e31SEd Tanous ec); 2508fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2509fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2510fdd26906SClaire Weinan return; 2511fdd26906SClaire Weinan } 2512fdd26906SClaire Weinan 2513fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2514fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2515fdd26906SClaire Weinan 2516fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2517fdd26906SClaire Weinan { 2518fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2519fdd26906SClaire Weinan { 2520613dabeaSEd Tanous nlohmann::json::object_t member; 2521*253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2522*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Dump", 2523*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2524b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2525fdd26906SClaire Weinan } 2526fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2527fdd26906SClaire Weinan { 2528613dabeaSEd Tanous nlohmann::json::object_t member; 2529*253f11b8SEd Tanous member["@odata.id"] = boost::urls::format( 2530*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/FaultLog", 2531*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2532b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2533fdd26906SClaire Weinan } 2534fdd26906SClaire Weinan } 2535fdd26906SClaire Weinan 2536e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2537fdd26906SClaire Weinan logServiceArrayLocal.size(); 25387a1dbc48SGeorge Liu }); 253925b54dbaSEd Tanous } 2540fdd26906SClaire Weinan } 2541fdd26906SClaire Weinan 2542fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2543fdd26906SClaire Weinan { 2544*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/") 2545fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2546fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2547dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2548e1f26343SJason M. Bills } 2549e1f26343SJason M. Bills 25507e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2551e1f26343SJason M. Bills { 2552*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/") 2553ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 25547e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 255545ca1b86SEd Tanous [&app](const crow::Request& req, 2556*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2557*253f11b8SEd Tanous const std::string& managerId) { 25583ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25597e860f15SJohn Edward Broadbent { 256045ca1b86SEd Tanous return; 256145ca1b86SEd Tanous } 2562*253f11b8SEd Tanous 2563*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2564*253f11b8SEd Tanous { 2565*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2566*253f11b8SEd Tanous return; 2567*253f11b8SEd Tanous } 2568*253f11b8SEd Tanous 2569e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2570b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 25710f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2572*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal", 2573*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2574002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2575002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2576ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2577e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 25787c8c4058STejas Patil 25797c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 25802b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2581002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 25827c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 25837c8c4058STejas Patil redfishDateTimeOffset.second; 25847c8c4058STejas Patil 2585*253f11b8SEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = boost::urls::format( 2586*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Journal/Entries", 2587*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 25887e860f15SJohn Edward Broadbent }); 2589e1f26343SJason M. Bills } 2590e1f26343SJason M. Bills 25913a48b3a2SJason M. Bills static int 25923a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2593e1f26343SJason M. Bills sd_journal* journal, 25943a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2595e1f26343SJason M. Bills { 2596e1f26343SJason M. Bills // Get the Log Entry contents 2597e1f26343SJason M. Bills int ret = 0; 2598e1f26343SJason M. Bills 2599a8fe54f0SJason M. Bills std::string message; 2600a8fe54f0SJason M. Bills std::string_view syslogID; 2601a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2602a8fe54f0SJason M. Bills if (ret < 0) 2603a8fe54f0SJason M. Bills { 2604bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 260562598e31SEd Tanous strerror(-ret)); 2606a8fe54f0SJason M. Bills } 2607a8fe54f0SJason M. Bills if (!syslogID.empty()) 2608a8fe54f0SJason M. Bills { 2609a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2610a8fe54f0SJason M. Bills } 2611a8fe54f0SJason M. Bills 261239e77504SEd Tanous std::string_view msg; 261316428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2614e1f26343SJason M. Bills if (ret < 0) 2615e1f26343SJason M. Bills { 261662598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2617e1f26343SJason M. Bills return 1; 2618e1f26343SJason M. Bills } 2619a8fe54f0SJason M. Bills message += std::string(msg); 2620e1f26343SJason M. Bills 2621e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2622271584abSEd Tanous long int severity = 8; // Default to an invalid priority 262316428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2624e1f26343SJason M. Bills if (ret < 0) 2625e1f26343SJason M. Bills { 2626bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2627e1f26343SJason M. Bills } 2628e1f26343SJason M. Bills 2629e1f26343SJason M. Bills // Get the Created time from the timestamp 263016428a1aSJason M. Bills std::string entryTimeStr; 263116428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2632e1f26343SJason M. Bills { 263316428a1aSJason M. Bills return 1; 2634e1f26343SJason M. Bills } 2635e1f26343SJason M. Bills 2636e1f26343SJason M. Bills // Fill in the log entry with the gathered data 26379c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2638ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2639*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Journal/Entries/{}", 2640*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, bmcJournalLogEntryID); 264184afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 264284afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 264384afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 264484afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 2645ddf3564eSEd Tanous log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK; 2646ddf3564eSEd Tanous if (severity <= 2) 2647ddf3564eSEd Tanous { 2648ddf3564eSEd Tanous severityEnum = log_entry::EventSeverity::Critical; 2649ddf3564eSEd Tanous } 2650ddf3564eSEd Tanous else if (severity <= 4) 2651ddf3564eSEd Tanous { 2652ddf3564eSEd Tanous severityEnum = log_entry::EventSeverity::Warning; 2653ddf3564eSEd Tanous } 2654ddf3564eSEd Tanous 2655ddf3564eSEd Tanous bmcJournalLogEntryJson["Severity"] = severityEnum; 265684afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 265784afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2658e1f26343SJason M. Bills return 0; 2659e1f26343SJason M. Bills } 2660e1f26343SJason M. Bills 26617e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2662e1f26343SJason M. Bills { 2663*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/") 2664ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2665002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2666002d39b4SEd Tanous [&app](const crow::Request& req, 2667*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2668*253f11b8SEd Tanous const std::string& managerId) { 2669c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2670c937d2bfSEd Tanous .canDelegateTop = true, 2671c937d2bfSEd Tanous .canDelegateSkip = true, 2672c937d2bfSEd Tanous }; 2673c937d2bfSEd Tanous query_param::Query delegatedQuery; 2674c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 26753ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2676193ad2faSJason M. Bills { 2677193ad2faSJason M. Bills return; 2678193ad2faSJason M. Bills } 26793648c8beSEd Tanous 2680*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2681*253f11b8SEd Tanous { 2682*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2683*253f11b8SEd Tanous return; 2684*253f11b8SEd Tanous } 2685*253f11b8SEd Tanous 26863648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 26875143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 26883648c8beSEd Tanous 26897e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 26907e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2691e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2692e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 2693*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2694*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Journal/Entries", 2695*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2696e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2697e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2698e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 26990fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2700e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2701e1f26343SJason M. Bills 27027e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 27037e860f15SJohn Edward Broadbent // unique ID for each entry 2704e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2705e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2706e1f26343SJason M. Bills if (ret < 0) 2707e1f26343SJason M. Bills { 270862598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2709f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2710e1f26343SJason M. Bills return; 2711e1f26343SJason M. Bills } 27120fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 27130fda0f12SGeorge Liu journalTmp, sd_journal_close); 2714e1f26343SJason M. Bills journalTmp = nullptr; 2715b01bf299SEd Tanous uint64_t entryCount = 0; 2716e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2717e85d6b16SJason M. Bills bool firstEntry = true; 2718e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2719e1f26343SJason M. Bills { 2720193ad2faSJason M. Bills entryCount++; 27217e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 27227e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 27233648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2724193ad2faSJason M. Bills { 2725193ad2faSJason M. Bills continue; 2726193ad2faSJason M. Bills } 2727193ad2faSJason M. Bills 272816428a1aSJason M. Bills std::string idStr; 2729e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2730e1f26343SJason M. Bills { 2731e1f26343SJason M. Bills continue; 2732e1f26343SJason M. Bills } 2733e85d6b16SJason M. Bills firstEntry = false; 2734e85d6b16SJason M. Bills 27353a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2736c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2737c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2738e1f26343SJason M. Bills { 2739f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2740e1f26343SJason M. Bills return; 2741e1f26343SJason M. Bills } 2742b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2743e1f26343SJason M. Bills } 2744193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 27453648c8beSEd Tanous if (skip + top < entryCount) 2746193ad2faSJason M. Bills { 2747*253f11b8SEd Tanous asyncResp->res 2748*253f11b8SEd Tanous .jsonValue["Members@odata.nextLink"] = boost::urls::format( 2749*253f11b8SEd Tanous "/redfish/v1/Managers/{}/LogServices/Journal/Entries?$skip={}", 2750*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, std::to_string(skip + top)); 2751193ad2faSJason M. Bills } 27527e860f15SJohn Edward Broadbent }); 2753e1f26343SJason M. Bills } 2754e1f26343SJason M. Bills 27557e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2756e1f26343SJason M. Bills { 2757*253f11b8SEd Tanous BMCWEB_ROUTE( 2758*253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/<str>/") 2759ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 27607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 276145ca1b86SEd Tanous [&app](const crow::Request& req, 27627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2763*253f11b8SEd Tanous const std::string& managerId, const std::string& entryID) { 27643ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 276545ca1b86SEd Tanous { 276645ca1b86SEd Tanous return; 276745ca1b86SEd Tanous } 2768*253f11b8SEd Tanous 2769*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2770*253f11b8SEd Tanous { 2771*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2772*253f11b8SEd Tanous return; 2773*253f11b8SEd Tanous } 2774*253f11b8SEd Tanous 2775e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 277675e8e218SMyung Bae sd_id128_t bootID{}; 2777e1f26343SJason M. Bills uint64_t ts = 0; 2778271584abSEd Tanous uint64_t index = 0; 277975e8e218SMyung Bae if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index)) 2780e1f26343SJason M. Bills { 278116428a1aSJason M. Bills return; 2782e1f26343SJason M. Bills } 2783e1f26343SJason M. Bills 2784e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2785e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2786e1f26343SJason M. Bills if (ret < 0) 2787e1f26343SJason M. Bills { 278862598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2789f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2790e1f26343SJason M. Bills return; 2791e1f26343SJason M. Bills } 2792002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2793002d39b4SEd Tanous journalTmp, sd_journal_close); 2794e1f26343SJason M. Bills journalTmp = nullptr; 27957e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 27967e860f15SJohn Edward Broadbent // index tracking the unique ID 2797af07e3f5SJason M. Bills std::string idStr; 2798af07e3f5SJason M. Bills bool firstEntry = true; 279975e8e218SMyung Bae ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts); 28002056b6d1SManojkiran Eda if (ret < 0) 28012056b6d1SManojkiran Eda { 280262598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 280362598e31SEd Tanous strerror(-ret)); 28042056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 28052056b6d1SManojkiran Eda return; 28062056b6d1SManojkiran Eda } 2807271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2808e1f26343SJason M. Bills { 2809e1f26343SJason M. Bills sd_journal_next(journal.get()); 2810af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2811af07e3f5SJason M. Bills { 2812af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2813af07e3f5SJason M. Bills return; 2814af07e3f5SJason M. Bills } 2815af07e3f5SJason M. Bills firstEntry = false; 2816af07e3f5SJason M. Bills } 2817c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2818af07e3f5SJason M. Bills if (idStr != entryID) 2819c4bf6374SJason M. Bills { 28209db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2821c4bf6374SJason M. Bills return; 2822c4bf6374SJason M. Bills } 2823c4bf6374SJason M. Bills 28243a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2825c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 28263a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2827e1f26343SJason M. Bills { 2828f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2829e1f26343SJason M. Bills return; 2830e1f26343SJason M. Bills } 2831d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 28327e860f15SJohn Edward Broadbent }); 2833c9bb6861Sraviteja-b } 2834c9bb6861Sraviteja-b 2835fdd26906SClaire Weinan inline void 2836fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2837fdd26906SClaire Weinan const std::string& dumpType) 2838c9bb6861Sraviteja-b { 2839fdd26906SClaire Weinan std::string dumpPath; 2840fdd26906SClaire Weinan std::string overWritePolicy; 2841fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2842fdd26906SClaire Weinan 2843fdd26906SClaire Weinan if (dumpType == "BMC") 284445ca1b86SEd Tanous { 2845*253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump", 2846*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2847fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2848fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2849fdd26906SClaire Weinan } 2850fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2851fdd26906SClaire Weinan { 2852*253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog", 2853*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2854fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2855fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2856fdd26906SClaire Weinan } 2857fdd26906SClaire Weinan else if (dumpType == "System") 2858fdd26906SClaire Weinan { 2859*253f11b8SEd Tanous dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump", 2860*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2861fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2862fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2863fdd26906SClaire Weinan } 2864fdd26906SClaire Weinan else 2865fdd26906SClaire Weinan { 286662598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 286762598e31SEd Tanous dumpType); 2868fdd26906SClaire Weinan messages::internalError(asyncResp->res); 286945ca1b86SEd Tanous return; 287045ca1b86SEd Tanous } 2871fdd26906SClaire Weinan 2872fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2873fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2874c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2875fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2876fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2877fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 28787c8c4058STejas Patil 28797c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 28802b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 28810fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 28827c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 28837c8c4058STejas Patil redfishDateTimeOffset.second; 28847c8c4058STejas Patil 2885fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2886fdd26906SClaire Weinan 2887fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2888fdd26906SClaire Weinan { 2889002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 28901476687dSEd Tanous ["target"] = 2891fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2892fdd26906SClaire Weinan } 28930d946211SClaire Weinan 28940d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 28950d946211SClaire Weinan dbus::utility::getSubTreePaths( 28960d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 28970d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 28980d946211SClaire Weinan const boost::system::error_code& ec, 28990d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 29000d946211SClaire Weinan if (ec) 29010d946211SClaire Weinan { 290262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 29030d946211SClaire Weinan // Assume that getting an error simply means there are no dump 29040d946211SClaire Weinan // LogServices. Return without adding any error response. 29050d946211SClaire Weinan return; 29060d946211SClaire Weinan } 290718f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 29080d946211SClaire Weinan for (const std::string& path : subTreePaths) 29090d946211SClaire Weinan { 29100d946211SClaire Weinan if (path == dbusDumpPath) 29110d946211SClaire Weinan { 29120d946211SClaire Weinan asyncResp->res 29130d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 29140d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 29150d946211SClaire Weinan break; 29160d946211SClaire Weinan } 29170d946211SClaire Weinan } 29180d946211SClaire Weinan }); 2919c9bb6861Sraviteja-b } 2920c9bb6861Sraviteja-b 2921fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2922fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2923*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2924*253f11b8SEd Tanous const std::string& managerId) 29257e860f15SJohn Edward Broadbent { 29263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 292745ca1b86SEd Tanous { 292845ca1b86SEd Tanous return; 292945ca1b86SEd Tanous } 2930*253f11b8SEd Tanous 2931*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2932*253f11b8SEd Tanous { 2933*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2934*253f11b8SEd Tanous return; 2935*253f11b8SEd Tanous } 2936*253f11b8SEd Tanous 2937fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2938fdd26906SClaire Weinan } 2939c9bb6861Sraviteja-b 294022d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 294122d268cbSEd Tanous crow::App& app, const crow::Request& req, 294222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 294322d268cbSEd Tanous const std::string& chassisId) 294422d268cbSEd Tanous { 294522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 294622d268cbSEd Tanous { 294722d268cbSEd Tanous return; 294822d268cbSEd Tanous } 2949*253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 295022d268cbSEd Tanous { 295122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 295222d268cbSEd Tanous return; 295322d268cbSEd Tanous } 295422d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 295522d268cbSEd Tanous } 295622d268cbSEd Tanous 2957fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2958fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2959*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2960*253f11b8SEd Tanous const std::string& managerId) 2961fdd26906SClaire Weinan { 2962fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2963fdd26906SClaire Weinan { 2964fdd26906SClaire Weinan return; 2965fdd26906SClaire Weinan } 2966*253f11b8SEd Tanous 2967*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2968*253f11b8SEd Tanous { 2969*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2970*253f11b8SEd Tanous return; 2971*253f11b8SEd Tanous } 2972fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2973fdd26906SClaire Weinan } 2974fdd26906SClaire Weinan 297522d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 297622d268cbSEd Tanous crow::App& app, const crow::Request& req, 297722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297822d268cbSEd Tanous const std::string& chassisId) 297922d268cbSEd Tanous { 298022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 298122d268cbSEd Tanous { 298222d268cbSEd Tanous return; 298322d268cbSEd Tanous } 2984*253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 298522d268cbSEd Tanous { 298622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 298722d268cbSEd Tanous return; 298822d268cbSEd Tanous } 298922d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 299022d268cbSEd Tanous } 299122d268cbSEd Tanous 2992fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2993fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2994fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2995*253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 2996fdd26906SClaire Weinan { 2997fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2998fdd26906SClaire Weinan { 2999fdd26906SClaire Weinan return; 3000fdd26906SClaire Weinan } 3001*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 3002*253f11b8SEd Tanous { 3003*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 3004*253f11b8SEd Tanous return; 3005*253f11b8SEd Tanous } 3006fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 3007fdd26906SClaire Weinan } 3008168d1b1aSCarson Labrado 300922d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 301022d268cbSEd Tanous crow::App& app, const crow::Request& req, 301122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 301222d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 301322d268cbSEd Tanous { 301422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 301522d268cbSEd Tanous { 301622d268cbSEd Tanous return; 301722d268cbSEd Tanous } 3018*253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 301922d268cbSEd Tanous { 302022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 302122d268cbSEd Tanous return; 302222d268cbSEd Tanous } 302322d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 302422d268cbSEd Tanous } 3025fdd26906SClaire Weinan 3026fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 3027fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3028fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3029*253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 3030fdd26906SClaire Weinan { 3031fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3032fdd26906SClaire Weinan { 3033fdd26906SClaire Weinan return; 3034fdd26906SClaire Weinan } 3035*253f11b8SEd Tanous 3036*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 3037*253f11b8SEd Tanous { 3038*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 3039*253f11b8SEd Tanous return; 3040*253f11b8SEd Tanous } 3041fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 3042fdd26906SClaire Weinan } 3043fdd26906SClaire Weinan 304422d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 304522d268cbSEd Tanous crow::App& app, const crow::Request& req, 304622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 304722d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 304822d268cbSEd Tanous { 304922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 305022d268cbSEd Tanous { 305122d268cbSEd Tanous return; 305222d268cbSEd Tanous } 3053*253f11b8SEd Tanous if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME) 305422d268cbSEd Tanous { 305522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 305622d268cbSEd Tanous return; 305722d268cbSEd Tanous } 305822d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 305922d268cbSEd Tanous } 306022d268cbSEd Tanous 3061168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 3062168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 3063168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3064*253f11b8SEd Tanous const std::string& managerId, const std::string& dumpId) 3065168d1b1aSCarson Labrado { 3066168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3067168d1b1aSCarson Labrado { 3068168d1b1aSCarson Labrado return; 3069168d1b1aSCarson Labrado } 3070*253f11b8SEd Tanous 3071*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 3072*253f11b8SEd Tanous { 3073*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 3074*253f11b8SEd Tanous return; 3075*253f11b8SEd Tanous } 3076168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 3077168d1b1aSCarson Labrado } 3078168d1b1aSCarson Labrado 3079168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 3080168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 3081168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3082168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 3083168d1b1aSCarson Labrado { 3084168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3085168d1b1aSCarson Labrado { 3086168d1b1aSCarson Labrado return; 3087168d1b1aSCarson Labrado } 3088168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 3089168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 3090168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 3091168d1b1aSCarson Labrado { 3092168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 3093168d1b1aSCarson Labrado return; 3094168d1b1aSCarson Labrado } 3095168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 3096168d1b1aSCarson Labrado } 3097168d1b1aSCarson Labrado 3098fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 3099fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3100*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3101*253f11b8SEd Tanous const std::string& managerId) 3102fdd26906SClaire Weinan { 3103fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3104fdd26906SClaire Weinan { 3105fdd26906SClaire Weinan return; 3106fdd26906SClaire Weinan } 3107*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 3108*253f11b8SEd Tanous { 3109*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 3110*253f11b8SEd Tanous return; 3111*253f11b8SEd Tanous } 3112*253f11b8SEd Tanous 3113fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 3114fdd26906SClaire Weinan } 3115fdd26906SClaire Weinan 311622d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 311722d268cbSEd Tanous crow::App& app, const crow::Request& req, 311822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 31197f3e84a1SEd Tanous const std::string& systemName) 312022d268cbSEd Tanous { 312122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 312222d268cbSEd Tanous { 312322d268cbSEd Tanous return; 312422d268cbSEd Tanous } 31257f3e84a1SEd Tanous 312625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 312722d268cbSEd Tanous { 31287f3e84a1SEd Tanous // Option currently returns no systems. TBD 31297f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31307f3e84a1SEd Tanous systemName); 31317f3e84a1SEd Tanous return; 31327f3e84a1SEd Tanous } 3133*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 31347f3e84a1SEd Tanous { 31357f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31367f3e84a1SEd Tanous systemName); 313722d268cbSEd Tanous return; 313822d268cbSEd Tanous } 313922d268cbSEd Tanous createDump(asyncResp, req, "System"); 314022d268cbSEd Tanous } 314122d268cbSEd Tanous 3142fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 3143fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3144*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3145*253f11b8SEd Tanous const std::string& managerId) 3146fdd26906SClaire Weinan { 3147fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3148fdd26906SClaire Weinan { 3149fdd26906SClaire Weinan return; 3150fdd26906SClaire Weinan } 3151*253f11b8SEd Tanous 3152*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 3153*253f11b8SEd Tanous { 3154*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 3155*253f11b8SEd Tanous return; 3156*253f11b8SEd Tanous } 3157fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 3158fdd26906SClaire Weinan } 3159fdd26906SClaire Weinan 316022d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 316122d268cbSEd Tanous crow::App& app, const crow::Request& req, 316222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 31637f3e84a1SEd Tanous const std::string& systemName) 316422d268cbSEd Tanous { 316522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 316622d268cbSEd Tanous { 316722d268cbSEd Tanous return; 316822d268cbSEd Tanous } 316925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 317022d268cbSEd Tanous { 31717f3e84a1SEd Tanous // Option currently returns no systems. TBD 31727f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31737f3e84a1SEd Tanous systemName); 31747f3e84a1SEd Tanous return; 31757f3e84a1SEd Tanous } 3176*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 31777f3e84a1SEd Tanous { 31787f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31797f3e84a1SEd Tanous systemName); 318022d268cbSEd Tanous return; 318122d268cbSEd Tanous } 318222d268cbSEd Tanous clearDump(asyncResp, "System"); 318322d268cbSEd Tanous } 318422d268cbSEd Tanous 3185fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 3186fdd26906SClaire Weinan { 3187*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/") 3188fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3189fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3190fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 3191fdd26906SClaire Weinan } 3192fdd26906SClaire Weinan 3193fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 3194fdd26906SClaire Weinan { 3195*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/") 3196fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3197fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3198fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 3199c9bb6861Sraviteja-b } 3200c9bb6861Sraviteja-b 32017e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 3202c9bb6861Sraviteja-b { 32037e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 3204*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 3205ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 3206fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3207fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 3208fdd26906SClaire Weinan 32097e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 3210*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/") 3211ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 3212fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3213fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 3214c9bb6861Sraviteja-b } 3215c9bb6861Sraviteja-b 3216168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 3217168d1b1aSCarson Labrado { 3218168d1b1aSCarson Labrado BMCWEB_ROUTE( 3219168d1b1aSCarson Labrado app, 3220*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/") 3221168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3222168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3223168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 3224168d1b1aSCarson Labrado } 3225168d1b1aSCarson Labrado 32267e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 3227c9bb6861Sraviteja-b { 32280fda0f12SGeorge Liu BMCWEB_ROUTE( 32290fda0f12SGeorge Liu app, 3230*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3231ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 32327e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 3233fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 3234fdd26906SClaire Weinan std::ref(app), "BMC")); 3235a43be80fSAsmitha Karunanithi } 3236a43be80fSAsmitha Karunanithi 32377e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 323880319af1SAsmitha Karunanithi { 32390fda0f12SGeorge Liu BMCWEB_ROUTE( 32400fda0f12SGeorge Liu app, 3241*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3242ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 3243fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3244fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 324545ca1b86SEd Tanous } 3246fdd26906SClaire Weinan 3247168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 3248168d1b1aSCarson Labrado { 3249168d1b1aSCarson Labrado BMCWEB_ROUTE( 3250168d1b1aSCarson Labrado app, 32519e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 3252168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3253168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3254168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 3255168d1b1aSCarson Labrado } 3256168d1b1aSCarson Labrado 3257fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3258fdd26906SClaire Weinan { 3259*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/") 3260fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3261fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3262fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3263fdd26906SClaire Weinan } 3264fdd26906SClaire Weinan 3265fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3266fdd26906SClaire Weinan { 3267*253f11b8SEd Tanous BMCWEB_ROUTE(app, 3268*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/") 3269fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3270fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3271fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3272fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3273fdd26906SClaire Weinan } 3274fdd26906SClaire Weinan 3275fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3276fdd26906SClaire Weinan { 3277*253f11b8SEd Tanous BMCWEB_ROUTE( 3278*253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 3279fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3280fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3281fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3282fdd26906SClaire Weinan 3283*253f11b8SEd Tanous BMCWEB_ROUTE( 3284*253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/") 3285fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3286fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3287fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3288fdd26906SClaire Weinan } 3289fdd26906SClaire Weinan 3290fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3291fdd26906SClaire Weinan { 3292fdd26906SClaire Weinan BMCWEB_ROUTE( 3293fdd26906SClaire Weinan app, 3294*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/") 3295fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3296fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3297fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 32985cb1dd27SAsmitha Karunanithi } 32995cb1dd27SAsmitha Karunanithi 33007e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 33015cb1dd27SAsmitha Karunanithi { 330222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3303ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 33046ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 330522d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 33065cb1dd27SAsmitha Karunanithi } 33075cb1dd27SAsmitha Karunanithi 33087e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 33097e860f15SJohn Edward Broadbent { 331022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3311ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 331222d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 331322d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 331422d268cbSEd Tanous std::ref(app))); 33155cb1dd27SAsmitha Karunanithi } 33165cb1dd27SAsmitha Karunanithi 33177e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 33185cb1dd27SAsmitha Karunanithi { 33197e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 332022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3321ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 33226ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 332322d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 33248d1b46d7Szhanghch05 33257e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 332622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3327ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 33286ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 332922d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 33305cb1dd27SAsmitha Karunanithi } 3331c9bb6861Sraviteja-b 33327e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3333c9bb6861Sraviteja-b { 33340fda0f12SGeorge Liu BMCWEB_ROUTE( 33350fda0f12SGeorge Liu app, 333622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3337ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 333822d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 333922d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 334022d268cbSEd Tanous std::ref(app))); 3341a43be80fSAsmitha Karunanithi } 3342a43be80fSAsmitha Karunanithi 33437e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3344a43be80fSAsmitha Karunanithi { 33450fda0f12SGeorge Liu BMCWEB_ROUTE( 33460fda0f12SGeorge Liu app, 334722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3348ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 33496ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 335022d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3351013487e5Sraviteja-b } 3352013487e5Sraviteja-b 33537e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 33541da66f75SEd Tanous { 33553946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33563946028dSAppaRao Puli // method for security reasons. 33571da66f75SEd Tanous /** 33581da66f75SEd Tanous * Functions triggers appropriate requests on DBus 33591da66f75SEd Tanous */ 336022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3361ed398213SEd Tanous // This is incorrect, should be: 3362ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3363432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3364002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3365002d39b4SEd Tanous [&app](const crow::Request& req, 336622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 336722d268cbSEd Tanous const std::string& systemName) { 33683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 336945ca1b86SEd Tanous { 337045ca1b86SEd Tanous return; 337145ca1b86SEd Tanous } 337225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 33737f3e84a1SEd Tanous { 33747f3e84a1SEd Tanous // Option currently returns no systems. TBD 33757f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33767f3e84a1SEd Tanous systemName); 33777f3e84a1SEd Tanous return; 33787f3e84a1SEd Tanous } 3379*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 338022d268cbSEd Tanous { 338122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 338222d268cbSEd Tanous systemName); 338322d268cbSEd Tanous return; 338422d268cbSEd Tanous } 338522d268cbSEd Tanous 33867e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 33877e860f15SJohn Edward Broadbent // SubRoute 33880f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3389*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump", 3390*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3391e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 33928e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 33934f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 33944f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 339515b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3396e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3397e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 33987c8c4058STejas Patil 33997c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 34002b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 34017c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 34027c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 34037c8c4058STejas Patil redfishDateTimeOffset.second; 34047c8c4058STejas Patil 34051476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3406*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 3407*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3408*253f11b8SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] 3409*253f11b8SEd Tanous ["target"] = std::format( 3410*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog", 3411*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3412002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 3413*253f11b8SEd Tanous ["target"] = std::format( 3414*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData", 3415*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 34167e860f15SJohn Edward Broadbent }); 34171da66f75SEd Tanous } 34181da66f75SEd Tanous 34197e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 34205b61b5e8SJason M. Bills { 34210fda0f12SGeorge Liu BMCWEB_ROUTE( 34220fda0f12SGeorge Liu app, 342322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3424ed398213SEd Tanous // This is incorrect, should be: 3425ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3426432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 34277e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 342845ca1b86SEd Tanous [&app](const crow::Request& req, 342922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 343022d268cbSEd Tanous const std::string& systemName) { 34313ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 343245ca1b86SEd Tanous { 343345ca1b86SEd Tanous return; 343445ca1b86SEd Tanous } 343525b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 34367f3e84a1SEd Tanous { 34377f3e84a1SEd Tanous // Option currently returns no systems. TBD 34387f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34397f3e84a1SEd Tanous systemName); 34407f3e84a1SEd Tanous return; 34417f3e84a1SEd Tanous } 3442*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 344322d268cbSEd Tanous { 344422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 344522d268cbSEd Tanous systemName); 344622d268cbSEd Tanous return; 344722d268cbSEd Tanous } 34485b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 34495e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3450cb13a392SEd Tanous const std::string&) { 34515b61b5e8SJason M. Bills if (ec) 34525b61b5e8SJason M. Bills { 34535b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 34545b61b5e8SJason M. Bills return; 34555b61b5e8SJason M. Bills } 34565b61b5e8SJason M. Bills messages::success(asyncResp->res); 34575b61b5e8SJason M. Bills }, 3458002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 34597e860f15SJohn Edward Broadbent }); 34605b61b5e8SJason M. Bills } 34615b61b5e8SJason M. Bills 34628d1b46d7Szhanghch05 static void 34638d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 34648d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3465e855dd28SJason M. Bills { 3466043a0536SJohnathan Mantey auto getStoredLogCallback = 3467b9d36b47SEd Tanous [asyncResp, logID, 34685e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3469b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3470e855dd28SJason M. Bills if (ec) 3471e855dd28SJason M. Bills { 347262598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 34731ddcf01aSJason M. Bills if (ec.value() == 34741ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 34751ddcf01aSJason M. Bills { 3476002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 34771ddcf01aSJason M. Bills } 34781ddcf01aSJason M. Bills else 34791ddcf01aSJason M. Bills { 3480e855dd28SJason M. Bills messages::internalError(asyncResp->res); 34811ddcf01aSJason M. Bills } 3482e855dd28SJason M. Bills return; 3483e855dd28SJason M. Bills } 3484043a0536SJohnathan Mantey 3485043a0536SJohnathan Mantey std::string timestamp{}; 3486043a0536SJohnathan Mantey std::string filename{}; 3487043a0536SJohnathan Mantey std::string logfile{}; 34882c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3489043a0536SJohnathan Mantey 3490043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3491e855dd28SJason M. Bills { 34929db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3493e855dd28SJason M. Bills return; 3494e855dd28SJason M. Bills } 3495e855dd28SJason M. Bills 3496043a0536SJohnathan Mantey std::string crashdumpURI = 3497*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/", 3498*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 3499043a0536SJohnathan Mantey logID + "/" + filename; 350084afc48bSJason M. Bills nlohmann::json::object_t logEntry; 35019c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3502ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3503*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}", 3504*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, logID); 350584afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 350684afc48bSJason M. Bills logEntry["Id"] = logID; 350784afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 350884afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 350984afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 351084afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 351184afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 35122b20ef6eSJason M. Bills 35132b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 35142b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 35152b20ef6eSJason M. Bills // directly 35162b20ef6eSJason M. Bills if (logEntryJson.is_array()) 35172b20ef6eSJason M. Bills { 35182b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 35192b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 35202b20ef6eSJason M. Bills logEntryJson.size(); 35212b20ef6eSJason M. Bills } 35222b20ef6eSJason M. Bills else 35232b20ef6eSJason M. Bills { 3524d405bb51SJason M. Bills logEntryJson.update(logEntry); 35252b20ef6eSJason M. Bills } 3526e855dd28SJason M. Bills }; 3527d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3528d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3529d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3530d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3531e855dd28SJason M. Bills } 3532e855dd28SJason M. Bills 35337e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 35341da66f75SEd Tanous { 35353946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 35363946028dSAppaRao Puli // method for security reasons. 35371da66f75SEd Tanous /** 35381da66f75SEd Tanous * Functions triggers appropriate requests on DBus 35391da66f75SEd Tanous */ 35407e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 354122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3542ed398213SEd Tanous // This is incorrect, should be. 3543ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3544432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3545002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3546002d39b4SEd Tanous [&app](const crow::Request& req, 354722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 354822d268cbSEd Tanous const std::string& systemName) { 35493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 355045ca1b86SEd Tanous { 355145ca1b86SEd Tanous return; 355245ca1b86SEd Tanous } 355325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 35547f3e84a1SEd Tanous { 35557f3e84a1SEd Tanous // Option currently returns no systems. TBD 35567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35577f3e84a1SEd Tanous systemName); 35587f3e84a1SEd Tanous return; 35597f3e84a1SEd Tanous } 3560*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 356122d268cbSEd Tanous { 356222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 356322d268cbSEd Tanous systemName); 356422d268cbSEd Tanous return; 356522d268cbSEd Tanous } 356622d268cbSEd Tanous 35677a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 35687a1dbc48SGeorge Liu crashdumpInterface}; 35697a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 35707a1dbc48SGeorge Liu "/", 0, interfaces, 35717a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 35722b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 35731da66f75SEd Tanous if (ec) 35741da66f75SEd Tanous { 35751da66f75SEd Tanous if (ec.value() != 35761da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 35771da66f75SEd Tanous { 357862598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 357962598e31SEd Tanous ec.message()); 3580f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35811da66f75SEd Tanous return; 35821da66f75SEd Tanous } 35831da66f75SEd Tanous } 3584e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 35851da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 3586*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 3587*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries", 3588*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 3589002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3590e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3591424c4176SJason M. Bills "Collection of Crashdump Entries"; 3592002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3593a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 35942b20ef6eSJason M. Bills 35952b20ef6eSJason M. Bills for (const std::string& path : resp) 35961da66f75SEd Tanous { 35972b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3598e855dd28SJason M. Bills // Get the log ID 35992b20ef6eSJason M. Bills std::string logID = objPath.filename(); 36002b20ef6eSJason M. Bills if (logID.empty()) 36011da66f75SEd Tanous { 3602e855dd28SJason M. Bills continue; 36031da66f75SEd Tanous } 3604e855dd28SJason M. Bills // Add the log entry to the array 36052b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 36062b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 36071da66f75SEd Tanous } 36087a1dbc48SGeorge Liu }); 36097e860f15SJohn Edward Broadbent }); 36101da66f75SEd Tanous } 36111da66f75SEd Tanous 36127e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 36131da66f75SEd Tanous { 36143946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 36153946028dSAppaRao Puli // method for security reasons. 36161da66f75SEd Tanous 36177e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 361822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3619ed398213SEd Tanous // this is incorrect, should be 3620ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3621432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 36227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 362345ca1b86SEd Tanous [&app](const crow::Request& req, 36247e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 362522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 36263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 362745ca1b86SEd Tanous { 362845ca1b86SEd Tanous return; 362945ca1b86SEd Tanous } 363025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 36317f3e84a1SEd Tanous { 36327f3e84a1SEd Tanous // Option currently returns no systems. TBD 36337f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36347f3e84a1SEd Tanous systemName); 36357f3e84a1SEd Tanous return; 36367f3e84a1SEd Tanous } 3637*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 363822d268cbSEd Tanous { 363922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 364022d268cbSEd Tanous systemName); 364122d268cbSEd Tanous return; 364222d268cbSEd Tanous } 36437e860f15SJohn Edward Broadbent const std::string& logID = param; 3644e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 36457e860f15SJohn Edward Broadbent }); 3646e855dd28SJason M. Bills } 3647e855dd28SJason M. Bills 36487e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3649e855dd28SJason M. Bills { 36503946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 36513946028dSAppaRao Puli // method for security reasons. 36527e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 36537e860f15SJohn Edward Broadbent app, 365422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3655ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 36567e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3657a4ce114aSNan Zhou [](const crow::Request& req, 36587e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 365922d268cbSEd Tanous const std::string& systemName, const std::string& logID, 366022d268cbSEd Tanous const std::string& fileName) { 36612a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 36622a9beeedSShounak Mitra // Redfish resource. 366322d268cbSEd Tanous 366425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 36657f3e84a1SEd Tanous { 36667f3e84a1SEd Tanous // Option currently returns no systems. TBD 36677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36687f3e84a1SEd Tanous systemName); 36697f3e84a1SEd Tanous return; 36707f3e84a1SEd Tanous } 3671*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 367222d268cbSEd Tanous { 367322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 367422d268cbSEd Tanous systemName); 367522d268cbSEd Tanous return; 367622d268cbSEd Tanous } 367722d268cbSEd Tanous 3678043a0536SJohnathan Mantey auto getStoredLogCallback = 367939662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 36805e7e2dc5SEd Tanous const boost::system::error_code& ec, 3681002d39b4SEd Tanous const std::vector< 3682002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 36837e860f15SJohn Edward Broadbent resp) { 36841da66f75SEd Tanous if (ec) 36851da66f75SEd Tanous { 368662598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3687f12894f8SJason M. Bills messages::internalError(asyncResp->res); 36881da66f75SEd Tanous return; 36891da66f75SEd Tanous } 3690e855dd28SJason M. Bills 3691043a0536SJohnathan Mantey std::string dbusFilename{}; 3692043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3693043a0536SJohnathan Mantey std::string dbusFilepath{}; 3694043a0536SJohnathan Mantey 3695002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3696002d39b4SEd Tanous dbusFilepath); 3697043a0536SJohnathan Mantey 3698043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3699043a0536SJohnathan Mantey dbusFilepath.empty()) 37001da66f75SEd Tanous { 37019db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 37021da66f75SEd Tanous return; 37031da66f75SEd Tanous } 3704e855dd28SJason M. Bills 3705043a0536SJohnathan Mantey // Verify the file name parameter is correct 3706043a0536SJohnathan Mantey if (fileName != dbusFilename) 3707043a0536SJohnathan Mantey { 37089db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3709043a0536SJohnathan Mantey return; 3710043a0536SJohnathan Mantey } 3711043a0536SJohnathan Mantey 371227b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3713043a0536SJohnathan Mantey { 37149db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3715043a0536SJohnathan Mantey return; 3716043a0536SJohnathan Mantey } 3717043a0536SJohnathan Mantey 37187e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 37197e860f15SJohn Edward Broadbent // from a browser 3720d9f6c621SEd Tanous asyncResp->res.addHeader( 3721d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 37221da66f75SEd Tanous }; 3723d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3724d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3725d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3726d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 37277e860f15SJohn Edward Broadbent }); 37281da66f75SEd Tanous } 37291da66f75SEd Tanous 3730c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3731c5a4c82aSJason M. Bills { 3732c5a4c82aSJason M. Bills onDemand, 3733c5a4c82aSJason M. Bills telemetry, 3734c5a4c82aSJason M. Bills invalid, 3735c5a4c82aSJason M. Bills }; 3736c5a4c82aSJason M. Bills 373726ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3738c5a4c82aSJason M. Bills { 3739c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3740c5a4c82aSJason M. Bills { 3741c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3742c5a4c82aSJason M. Bills } 3743c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3744c5a4c82aSJason M. Bills { 3745c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3746c5a4c82aSJason M. Bills } 3747c5a4c82aSJason M. Bills 3748c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3749c5a4c82aSJason M. Bills } 3750c5a4c82aSJason M. Bills 37517e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 37521da66f75SEd Tanous { 37533946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 37543946028dSAppaRao Puli // method for security reasons. 37550fda0f12SGeorge Liu BMCWEB_ROUTE( 37560fda0f12SGeorge Liu app, 375722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3758ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3759ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3760432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3761002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3762002d39b4SEd Tanous [&app](const crow::Request& req, 376322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 376422d268cbSEd Tanous const std::string& systemName) { 37653ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 376645ca1b86SEd Tanous { 376745ca1b86SEd Tanous return; 376845ca1b86SEd Tanous } 376922d268cbSEd Tanous 377025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 37717f3e84a1SEd Tanous { 37727f3e84a1SEd Tanous // Option currently returns no systems. TBD 37737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37747f3e84a1SEd Tanous systemName); 37757f3e84a1SEd Tanous return; 37767f3e84a1SEd Tanous } 3777*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 377822d268cbSEd Tanous { 377922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 378022d268cbSEd Tanous systemName); 378122d268cbSEd Tanous return; 378222d268cbSEd Tanous } 378322d268cbSEd Tanous 37848e6c099aSJason M. Bills std::string diagnosticDataType; 37858e6c099aSJason M. Bills std::string oemDiagnosticDataType; 378615ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3787002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3788002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 37898e6c099aSJason M. Bills { 37908e6c099aSJason M. Bills return; 37918e6c099aSJason M. Bills } 37928e6c099aSJason M. Bills 37938e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 37948e6c099aSJason M. Bills { 379562598e31SEd Tanous BMCWEB_LOG_ERROR( 379662598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 37978e6c099aSJason M. Bills messages::actionParameterValueFormatError( 37988e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 37998e6c099aSJason M. Bills "CollectDiagnosticData"); 38008e6c099aSJason M. Bills return; 38018e6c099aSJason M. Bills } 38028e6c099aSJason M. Bills 3803c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3804c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3805c5a4c82aSJason M. Bills 3806c5a4c82aSJason M. Bills std::string iface; 3807c5a4c82aSJason M. Bills std::string method; 3808c5a4c82aSJason M. Bills std::string taskMatchStr; 3809c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3810c5a4c82aSJason M. Bills { 3811c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3812c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3813c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3814c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3815c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3816c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3817c5a4c82aSJason M. Bills } 3818c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3819c5a4c82aSJason M. Bills { 3820c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3821c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3822c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3823c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3824c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3825c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3826c5a4c82aSJason M. Bills } 3827c5a4c82aSJason M. Bills else 3828c5a4c82aSJason M. Bills { 382962598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 383062598e31SEd Tanous oemDiagnosticDataType); 3831c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3832002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3833002d39b4SEd Tanous "CollectDiagnosticData"); 3834c5a4c82aSJason M. Bills return; 3835c5a4c82aSJason M. Bills } 3836c5a4c82aSJason M. Bills 3837c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3838c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 38395e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 384098be3e39SEd Tanous const std::string&) mutable { 38411da66f75SEd Tanous if (ec) 38421da66f75SEd Tanous { 3843002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 38441da66f75SEd Tanous { 3845f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 38461da66f75SEd Tanous } 38474363d3b2SJason M. Bills else if (ec.value() == 38484363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 38494363d3b2SJason M. Bills { 3850002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3851002d39b4SEd Tanous "60"); 38524363d3b2SJason M. Bills } 38531da66f75SEd Tanous else 38541da66f75SEd Tanous { 3855f12894f8SJason M. Bills messages::internalError(asyncResp->res); 38561da66f75SEd Tanous } 38571da66f75SEd Tanous return; 38581da66f75SEd Tanous } 3859002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 38608b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3861002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 38628b24275dSEd Tanous if (!ec2) 386366afe4faSJames Feist { 3864002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3865e5d5006bSJames Feist std::to_string(taskData->index))); 3866831d6b09SJames Feist taskData->state = "Completed"; 386766afe4faSJames Feist } 386832898ceaSJames Feist return task::completed; 386966afe4faSJames Feist }, 3870c5a4c82aSJason M. Bills taskMatchStr); 3871c5a4c82aSJason M. Bills 387246229577SJames Feist task->startTimer(std::chrono::minutes(5)); 387346229577SJames Feist task->populateResp(asyncResp->res); 387498be3e39SEd Tanous task->payload.emplace(std::move(payload)); 38751da66f75SEd Tanous }; 38768e6c099aSJason M. Bills 38771da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3878002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3879002d39b4SEd Tanous iface, method); 38807e860f15SJohn Edward Broadbent }); 38816eda7685SKenny L. Ku } 38826eda7685SKenny L. Ku 3883cb92c03bSAndrew Geissler /** 3884cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3885cb92c03bSAndrew Geissler */ 38867e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3887cb92c03bSAndrew Geissler { 3888cb92c03bSAndrew Geissler /** 3889cb92c03bSAndrew Geissler * Function handles POST method request. 3890cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3891cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3892cb92c03bSAndrew Geissler */ 38937e860f15SJohn Edward Broadbent 38940fda0f12SGeorge Liu BMCWEB_ROUTE( 38950fda0f12SGeorge Liu app, 389622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3897ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 38987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 389945ca1b86SEd Tanous [&app](const crow::Request& req, 390022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 390122d268cbSEd Tanous const std::string& systemName) { 39023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 390345ca1b86SEd Tanous { 390445ca1b86SEd Tanous return; 390545ca1b86SEd Tanous } 390625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39077f3e84a1SEd Tanous { 39087f3e84a1SEd Tanous // Option currently returns no systems. TBD 39097f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39107f3e84a1SEd Tanous systemName); 39117f3e84a1SEd Tanous return; 39127f3e84a1SEd Tanous } 3913*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 391422d268cbSEd Tanous { 391522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 391622d268cbSEd Tanous systemName); 391722d268cbSEd Tanous return; 391822d268cbSEd Tanous } 391962598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3920cb92c03bSAndrew Geissler 3921cb92c03bSAndrew Geissler // Process response from Logging service. 39225e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 392362598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3924cb92c03bSAndrew Geissler if (ec) 3925cb92c03bSAndrew Geissler { 3926cb92c03bSAndrew Geissler // TODO Handle for specific error code 392762598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3928cb92c03bSAndrew Geissler asyncResp->res.result( 3929cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3930cb92c03bSAndrew Geissler return; 3931cb92c03bSAndrew Geissler } 3932cb92c03bSAndrew Geissler 3933002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3934cb92c03bSAndrew Geissler }; 3935cb92c03bSAndrew Geissler 3936cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3937cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 39382c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3939cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3940cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 39417e860f15SJohn Edward Broadbent }); 3942cb92c03bSAndrew Geissler } 3943a3316fc6SZhikuiRen 3944a3316fc6SZhikuiRen /**************************************************** 3945a3316fc6SZhikuiRen * Redfish PostCode interfaces 3946a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3947a3316fc6SZhikuiRen ******************************************************/ 39487e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3949a3316fc6SZhikuiRen { 395022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3951ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3952002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3953002d39b4SEd Tanous [&app](const crow::Request& req, 395422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 395522d268cbSEd Tanous const std::string& systemName) { 39563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 395745ca1b86SEd Tanous { 395845ca1b86SEd Tanous return; 395945ca1b86SEd Tanous } 396025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 39617f3e84a1SEd Tanous { 39627f3e84a1SEd Tanous // Option currently returns no systems. TBD 39637f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 39647f3e84a1SEd Tanous systemName); 39657f3e84a1SEd Tanous return; 39667f3e84a1SEd Tanous } 3967*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 396822d268cbSEd Tanous { 396922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 397022d268cbSEd Tanous systemName); 397122d268cbSEd Tanous return; 397222d268cbSEd Tanous } 39731476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3974*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes", 3975*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 39761476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3977b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 39781476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 39791476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3980ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 39811476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 39821476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3983*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 3984*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 39857c8c4058STejas Patil 39867c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 39872b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 39880fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 39897c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 39907c8c4058STejas Patil redfishDateTimeOffset.second; 39917c8c4058STejas Patil 3992a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 39937e860f15SJohn Edward Broadbent {"target", 3994*253f11b8SEd Tanous std::format( 3995*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog", 3996*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME)}}; 39977e860f15SJohn Edward Broadbent }); 3998a3316fc6SZhikuiRen } 3999a3316fc6SZhikuiRen 40007e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 4001a3316fc6SZhikuiRen { 40020fda0f12SGeorge Liu BMCWEB_ROUTE( 40030fda0f12SGeorge Liu app, 400422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 4005ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 4006ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 4007432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 40087e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 400945ca1b86SEd Tanous [&app](const crow::Request& req, 401022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 401122d268cbSEd Tanous const std::string& systemName) { 40123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 401345ca1b86SEd Tanous { 401445ca1b86SEd Tanous return; 401545ca1b86SEd Tanous } 401625b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 40177f3e84a1SEd Tanous { 40187f3e84a1SEd Tanous // Option currently returns no systems. TBD 40197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 40207f3e84a1SEd Tanous systemName); 40217f3e84a1SEd Tanous return; 40227f3e84a1SEd Tanous } 4023*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 402422d268cbSEd Tanous { 402522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 402622d268cbSEd Tanous systemName); 402722d268cbSEd Tanous return; 402822d268cbSEd Tanous } 402962598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 4030a3316fc6SZhikuiRen 4031a3316fc6SZhikuiRen // Make call to post-code service to request clear all 4032a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 40335e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 4034a3316fc6SZhikuiRen if (ec) 4035a3316fc6SZhikuiRen { 4036a3316fc6SZhikuiRen // TODO Handle for specific error code 403762598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 403862598e31SEd Tanous ec); 4039002d39b4SEd Tanous asyncResp->res.result( 4040002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 4041a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 4042a3316fc6SZhikuiRen return; 4043a3316fc6SZhikuiRen } 404418fc70c0STony Lee messages::success(asyncResp->res); 4045a3316fc6SZhikuiRen }, 404615124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 404715124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4048a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 40497e860f15SJohn Edward Broadbent }); 4050a3316fc6SZhikuiRen } 4051a3316fc6SZhikuiRen 40526f284d24SJiaqing Zhao /** 40536f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 40546f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 40556f284d24SJiaqing Zhao * 40566f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 40576f284d24SJiaqing Zhao * @param[out] currentValue Current value 40586f284d24SJiaqing Zhao * @param[out] index Index value 40596f284d24SJiaqing Zhao * 40606f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 40616f284d24SJiaqing Zhao */ 40626f056f24SEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue, 4063df254f2cSEd Tanous uint16_t& index) 40646f284d24SJiaqing Zhao { 40656f284d24SJiaqing Zhao std::vector<std::string> split; 406650ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 40676f056f24SEd Tanous if (split.size() != 2) 40686f056f24SEd Tanous { 40696f056f24SEd Tanous return false; 40706f056f24SEd Tanous } 40716f056f24SEd Tanous std::string_view postCodeNumber = split[0]; 40726f056f24SEd Tanous if (postCodeNumber.size() < 2) 40736f056f24SEd Tanous { 40746f056f24SEd Tanous return false; 40756f056f24SEd Tanous } 40766f056f24SEd Tanous if (postCodeNumber[0] != 'B') 40776f056f24SEd Tanous { 40786f056f24SEd Tanous return false; 40796f056f24SEd Tanous } 40806f056f24SEd Tanous postCodeNumber.remove_prefix(1); 40816f056f24SEd Tanous auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(), 40826f056f24SEd Tanous postCodeNumber.end(), index); 40836f056f24SEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc()) 40846f284d24SJiaqing Zhao { 40856f284d24SJiaqing Zhao return false; 40866f284d24SJiaqing Zhao } 40876f284d24SJiaqing Zhao 40886f056f24SEd Tanous std::string_view postCodeIndex = split[1]; 40896f284d24SJiaqing Zhao 40906f056f24SEd Tanous auto [ptrValue, ecValue] = std::from_chars( 40916f056f24SEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue); 40926f284d24SJiaqing Zhao 40936f056f24SEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc(); 40946f284d24SJiaqing Zhao } 40956f284d24SJiaqing Zhao 40966f284d24SJiaqing Zhao static bool fillPostCodeEntry( 4097ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40986c9a279eSManojkiran Eda const boost::container::flat_map< 40996c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 4100a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 4101a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 4102a3316fc6SZhikuiRen { 4103a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 4104fffb8c1fSEd Tanous const registries::Message* message = 4105fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 4106dc8cfa66SEd Tanous if (message == nullptr) 4107dc8cfa66SEd Tanous { 4108dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?"); 4109dc8cfa66SEd Tanous return false; 4110dc8cfa66SEd Tanous } 4111a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 4112a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 41136c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41146c9a279eSManojkiran Eda code : postcode) 4115a3316fc6SZhikuiRen { 4116a3316fc6SZhikuiRen currentCodeIndex++; 4117a3316fc6SZhikuiRen std::string postcodeEntryID = 4118a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 4119a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 4120a3316fc6SZhikuiRen 4121a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 4122a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 4123a3316fc6SZhikuiRen 4124a3316fc6SZhikuiRen if (1 == currentCodeIndex) 4125a3316fc6SZhikuiRen { // already incremented 4126a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 4127a3316fc6SZhikuiRen } 4128a3316fc6SZhikuiRen else 4129a3316fc6SZhikuiRen { 4130a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 4131a3316fc6SZhikuiRen } 4132a3316fc6SZhikuiRen 4133a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 4134a3316fc6SZhikuiRen // not fall between top and skip 4135a3316fc6SZhikuiRen if ((codeIndex == 0) && 4136a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 4137a3316fc6SZhikuiRen { 4138a3316fc6SZhikuiRen continue; 4139a3316fc6SZhikuiRen } 4140a3316fc6SZhikuiRen 41414e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 4142a3316fc6SZhikuiRen // currentIndex 4143a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 4144a3316fc6SZhikuiRen { 4145a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 4146a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 4147a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 4148a3316fc6SZhikuiRen continue; 4149a3316fc6SZhikuiRen } 4150a3316fc6SZhikuiRen 4151a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 4152a3316fc6SZhikuiRen // index 4153a3316fc6SZhikuiRen 4154a3316fc6SZhikuiRen // Get the Created time from the timestamp 4155a3316fc6SZhikuiRen std::string entryTimeStr; 41562a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 4157a3316fc6SZhikuiRen 4158a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 4159a3316fc6SZhikuiRen std::ostringstream hexCode; 4160a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 41616c9a279eSManojkiran Eda << std::get<0>(code.second); 4162a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 4163a3316fc6SZhikuiRen // Set Fixed -Point Notation 4164a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 4165a3316fc6SZhikuiRen // Set precision to 4 digits 4166a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 4167a3316fc6SZhikuiRen // Add double to stream 4168a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 4169a3316fc6SZhikuiRen 41701e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 41711e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 41721e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 4173a3316fc6SZhikuiRen 41741e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 41751e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 41761e6deaf6SEd Tanous 41771e6deaf6SEd Tanous std::string msg = 41781e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 41791e6deaf6SEd Tanous if (msg.empty()) 4180a3316fc6SZhikuiRen { 41811e6deaf6SEd Tanous messages::internalError(asyncResp->res); 41821e6deaf6SEd Tanous return false; 4183a3316fc6SZhikuiRen } 4184a3316fc6SZhikuiRen 4185d4342a92STim Lee // Get Severity template from message registry 4186d4342a92STim Lee std::string severity; 4187d4342a92STim Lee if (message != nullptr) 4188d4342a92STim Lee { 41895f2b84eeSEd Tanous severity = message->messageSeverity; 4190d4342a92STim Lee } 4191d4342a92STim Lee 41926f284d24SJiaqing Zhao // Format entry 41936f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 41949c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4195ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 4196*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}", 4197*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID); 419884afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 419984afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 420084afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 420184afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 42021e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 420384afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 420484afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 420584afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 4206647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 4207647b3cdcSGeorge Liu { 4208647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 4209*253f11b8SEd Tanous std::format( 4210*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/", 4211*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 4212647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 4213647b3cdcSGeorge Liu } 42146f284d24SJiaqing Zhao 42156f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 42166f284d24SJiaqing Zhao // that entry in this case 42176f284d24SJiaqing Zhao if (codeIndex != 0) 42186f284d24SJiaqing Zhao { 4219ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 42206f284d24SJiaqing Zhao return true; 4221a3316fc6SZhikuiRen } 42226f284d24SJiaqing Zhao 4223ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 4224b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 42256f284d24SJiaqing Zhao } 42266f284d24SJiaqing Zhao 42276f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 42286f284d24SJiaqing Zhao return false; 4229a3316fc6SZhikuiRen } 4230a3316fc6SZhikuiRen 4231ac106bf6SEd Tanous static void 4232ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42336f284d24SJiaqing Zhao const std::string& entryId) 4234a3316fc6SZhikuiRen { 42356f284d24SJiaqing Zhao uint16_t bootIndex = 0; 42366f284d24SJiaqing Zhao uint64_t codeIndex = 0; 42376f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 42386f284d24SJiaqing Zhao { 42396f284d24SJiaqing Zhao // Requested ID was not found 4240ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 42416f284d24SJiaqing Zhao return; 42426f284d24SJiaqing Zhao } 42436f284d24SJiaqing Zhao 42446f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 42456f284d24SJiaqing Zhao { 42466f284d24SJiaqing Zhao // 0 is an invalid index 4247ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 42486f284d24SJiaqing Zhao return; 42496f284d24SJiaqing Zhao } 42506f284d24SJiaqing Zhao 4251a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4252ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 42535e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 42546c9a279eSManojkiran Eda const boost::container::flat_map< 42556c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 42566c9a279eSManojkiran Eda postcode) { 4257a3316fc6SZhikuiRen if (ec) 4258a3316fc6SZhikuiRen { 425962598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4260ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4261a3316fc6SZhikuiRen return; 4262a3316fc6SZhikuiRen } 4263a3316fc6SZhikuiRen 4264a3316fc6SZhikuiRen if (postcode.empty()) 4265a3316fc6SZhikuiRen { 4266ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 4267a3316fc6SZhikuiRen return; 4268a3316fc6SZhikuiRen } 4269a3316fc6SZhikuiRen 4270ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 42716f284d24SJiaqing Zhao { 4272ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 42736f284d24SJiaqing Zhao return; 42746f284d24SJiaqing Zhao } 4275a3316fc6SZhikuiRen }, 427615124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 427715124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4278a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4279a3316fc6SZhikuiRen bootIndex); 4280a3316fc6SZhikuiRen } 4281a3316fc6SZhikuiRen 4282ac106bf6SEd Tanous static void 4283ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4284ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4285ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4286a3316fc6SZhikuiRen { 4287a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4288ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 42895e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 42906c9a279eSManojkiran Eda const boost::container::flat_map< 42916c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 42926c9a279eSManojkiran Eda postcode) { 4293a3316fc6SZhikuiRen if (ec) 4294a3316fc6SZhikuiRen { 429562598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4296ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4297a3316fc6SZhikuiRen return; 4298a3316fc6SZhikuiRen } 4299a3316fc6SZhikuiRen 4300a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4301a3316fc6SZhikuiRen if (!postcode.empty()) 4302a3316fc6SZhikuiRen { 4303a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 43043648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4305a3316fc6SZhikuiRen { 430689492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 430789492a15SPatrick Williams entryCount) - 43083648c8beSEd Tanous entryCount; 4309a3316fc6SZhikuiRen uint64_t thisBootTop = 43103648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 43113648c8beSEd Tanous entryCount; 4312a3316fc6SZhikuiRen 4313ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4314ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4315a3316fc6SZhikuiRen } 4316ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4317a3316fc6SZhikuiRen } 4318a3316fc6SZhikuiRen 4319a3316fc6SZhikuiRen // continue to previous bootIndex 4320a3316fc6SZhikuiRen if (bootIndex < bootCount) 4321a3316fc6SZhikuiRen { 4322ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4323a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4324a3316fc6SZhikuiRen } 432581584abeSJiaqing Zhao else if (skip + top < endCount) 4326a3316fc6SZhikuiRen { 4327ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 4328*253f11b8SEd Tanous std::format( 4329*253f11b8SEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=", 4330*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) + 4331a3316fc6SZhikuiRen std::to_string(skip + top); 4332a3316fc6SZhikuiRen } 4333a3316fc6SZhikuiRen }, 433415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 433515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4336a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4337a3316fc6SZhikuiRen bootIndex); 4338a3316fc6SZhikuiRen } 4339a3316fc6SZhikuiRen 43408d1b46d7Szhanghch05 static void 4341ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 43423648c8beSEd Tanous size_t skip, size_t top) 4343a3316fc6SZhikuiRen { 4344a3316fc6SZhikuiRen uint64_t entryCount = 0; 43451e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 43461e1e598dSJonathan Doman *crow::connections::systemBus, 43471e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 43481e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 43491e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4350ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 43511e1e598dSJonathan Doman const uint16_t bootCount) { 4352a3316fc6SZhikuiRen if (ec) 4353a3316fc6SZhikuiRen { 435462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4355ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4356a3316fc6SZhikuiRen return; 4357a3316fc6SZhikuiRen } 4358ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 43591e1e598dSJonathan Doman }); 4360a3316fc6SZhikuiRen } 4361a3316fc6SZhikuiRen 43627e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4363a3316fc6SZhikuiRen { 43647e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 436522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4366ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 43677e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 436845ca1b86SEd Tanous [&app](const crow::Request& req, 436922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 437022d268cbSEd Tanous const std::string& systemName) { 4371c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4372c937d2bfSEd Tanous .canDelegateTop = true, 4373c937d2bfSEd Tanous .canDelegateSkip = true, 4374c937d2bfSEd Tanous }; 4375c937d2bfSEd Tanous query_param::Query delegatedQuery; 4376c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 43773ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 437845ca1b86SEd Tanous { 437945ca1b86SEd Tanous return; 438045ca1b86SEd Tanous } 438125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 43827f3e84a1SEd Tanous { 43837f3e84a1SEd Tanous // Option currently returns no systems. TBD 43847f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 43857f3e84a1SEd Tanous systemName); 43867f3e84a1SEd Tanous return; 43877f3e84a1SEd Tanous } 438822d268cbSEd Tanous 4389*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 439022d268cbSEd Tanous { 439122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 439222d268cbSEd Tanous systemName); 439322d268cbSEd Tanous return; 439422d268cbSEd Tanous } 4395a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4396a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4397a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4398*253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries", 4399*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 4400a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4401a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4402a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4403a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4404a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 44053648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 44065143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 44073648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 44087e860f15SJohn Edward Broadbent }); 4409a3316fc6SZhikuiRen } 4410a3316fc6SZhikuiRen 4411647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4412647b3cdcSGeorge Liu { 44130fda0f12SGeorge Liu BMCWEB_ROUTE( 44140fda0f12SGeorge Liu app, 441522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4416647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4417647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 441845ca1b86SEd Tanous [&app](const crow::Request& req, 4419647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 442022d268cbSEd Tanous const std::string& systemName, 4421647b3cdcSGeorge Liu const std::string& postCodeID) { 44223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 442345ca1b86SEd Tanous { 442445ca1b86SEd Tanous return; 442545ca1b86SEd Tanous } 442672e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 442799351cd8SEd Tanous req.getHeaderValue("Accept"), 44284a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4429647b3cdcSGeorge Liu { 4430002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4431647b3cdcSGeorge Liu return; 4432647b3cdcSGeorge Liu } 443325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 44347f3e84a1SEd Tanous { 44357f3e84a1SEd Tanous // Option currently returns no systems. TBD 44367f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 44377f3e84a1SEd Tanous systemName); 44387f3e84a1SEd Tanous return; 44397f3e84a1SEd Tanous } 4440*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 444122d268cbSEd Tanous { 444222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 444322d268cbSEd Tanous systemName); 444422d268cbSEd Tanous return; 444522d268cbSEd Tanous } 4446647b3cdcSGeorge Liu 4447647b3cdcSGeorge Liu uint64_t currentValue = 0; 4448647b3cdcSGeorge Liu uint16_t index = 0; 4449647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4450647b3cdcSGeorge Liu { 4451002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4452647b3cdcSGeorge Liu return; 4453647b3cdcSGeorge Liu } 4454647b3cdcSGeorge Liu 4455647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4456647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 44575e7e2dc5SEd Tanous const boost::system::error_code& ec, 4458002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4459002d39b4SEd Tanous postcodes) { 4460647b3cdcSGeorge Liu if (ec.value() == EBADR) 4461647b3cdcSGeorge Liu { 4462002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4463002d39b4SEd Tanous postCodeID); 4464647b3cdcSGeorge Liu return; 4465647b3cdcSGeorge Liu } 4466647b3cdcSGeorge Liu if (ec) 4467647b3cdcSGeorge Liu { 446862598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4469647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4470647b3cdcSGeorge Liu return; 4471647b3cdcSGeorge Liu } 4472647b3cdcSGeorge Liu 4473647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4474002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4475647b3cdcSGeorge Liu { 447662598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4477002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4478002d39b4SEd Tanous postCodeID); 4479647b3cdcSGeorge Liu return; 4480647b3cdcSGeorge Liu } 4481647b3cdcSGeorge Liu 44829eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 448346ff87baSEd Tanous if (c.empty()) 4484647b3cdcSGeorge Liu { 448562598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4486002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4487002d39b4SEd Tanous postCodeID); 4488647b3cdcSGeorge Liu return; 4489647b3cdcSGeorge Liu } 449046ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 449146ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 449246ff87baSEd Tanous std::string_view strData(d, c.size()); 4493647b3cdcSGeorge Liu 4494d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4495647b3cdcSGeorge Liu "application/octet-stream"); 4496d9f6c621SEd Tanous asyncResp->res.addHeader( 4497d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 449827b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4499647b3cdcSGeorge Liu }, 4500647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4501647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4502002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4503647b3cdcSGeorge Liu }); 4504647b3cdcSGeorge Liu } 4505647b3cdcSGeorge Liu 45067e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4507a3316fc6SZhikuiRen { 45087e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 450922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4510ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 45117e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 451245ca1b86SEd Tanous [&app](const crow::Request& req, 45137e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 451422d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 45153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 451645ca1b86SEd Tanous { 451745ca1b86SEd Tanous return; 451845ca1b86SEd Tanous } 451925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 45207f3e84a1SEd Tanous { 45217f3e84a1SEd Tanous // Option currently returns no systems. TBD 45227f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 45237f3e84a1SEd Tanous systemName); 45247f3e84a1SEd Tanous return; 45257f3e84a1SEd Tanous } 4526*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 452722d268cbSEd Tanous { 452822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 452922d268cbSEd Tanous systemName); 453022d268cbSEd Tanous return; 453122d268cbSEd Tanous } 453222d268cbSEd Tanous 45336f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 45347e860f15SJohn Edward Broadbent }); 4535a3316fc6SZhikuiRen } 4536a3316fc6SZhikuiRen 45371da66f75SEd Tanous } // namespace redfish 4538