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" 313ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 323ccb3adbSEd Tanous #include "utils/time_utils.hpp" 331da66f75SEd Tanous 3475e8e218SMyung Bae #include <systemd/sd-id128.h> 35e1f26343SJason M. Bills #include <systemd/sd-journal.h> 368e31778eSAsmitha Karunanithi #include <tinyxml2.h> 37400fd1fbSAdriana Kobylak #include <unistd.h> 38e1f26343SJason M. Bills 3907c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 401da66f75SEd Tanous #include <boost/container/flat_map.hpp> 411ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 42ef4c65b7SEd Tanous #include <boost/url/format.hpp> 43d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 44d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 451214b7e7SGunnar Mills 467a1dbc48SGeorge Liu #include <array> 47647b3cdcSGeorge Liu #include <charconv> 484418c7f0SJames Feist #include <filesystem> 49*18f8f608SEd Tanous #include <iterator> 5075710de2SXiaochao Ma #include <optional> 513544d2a7SEd Tanous #include <ranges> 5226702d01SEd Tanous #include <span> 53*18f8f608SEd Tanous #include <string> 54cd225da8SJason M. Bills #include <string_view> 55abf2add6SEd Tanous #include <variant> 561da66f75SEd Tanous 571da66f75SEd Tanous namespace redfish 581da66f75SEd Tanous { 591da66f75SEd Tanous 6089492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6189492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6289492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6389492a15SPatrick Williams constexpr const char* deleteAllInterface = 645b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6589492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 66424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6789492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 686eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 691da66f75SEd Tanous 708e31778eSAsmitha Karunanithi enum class DumpCreationProgress 718e31778eSAsmitha Karunanithi { 728e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 738e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 748e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 758e31778eSAsmitha Karunanithi }; 768e31778eSAsmitha Karunanithi 77f6150403SJames Feist namespace fs = std::filesystem; 781da66f75SEd Tanous 79cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 80cb92c03bSAndrew Geissler { 81d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 82d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 85cb92c03bSAndrew Geissler { 86cb92c03bSAndrew Geissler return "Critical"; 87cb92c03bSAndrew Geissler } 883174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 89d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 90d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 91cb92c03bSAndrew Geissler { 92cb92c03bSAndrew Geissler return "OK"; 93cb92c03bSAndrew Geissler } 943174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 95cb92c03bSAndrew Geissler { 96cb92c03bSAndrew Geissler return "Warning"; 97cb92c03bSAndrew Geissler } 98cb92c03bSAndrew Geissler return ""; 99cb92c03bSAndrew Geissler } 100cb92c03bSAndrew Geissler 1019017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1029017faf2SAbhishek Patel { 1039017faf2SAbhishek Patel std::optional<bool> notifyAction; 1049017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1059017faf2SAbhishek Patel { 1069017faf2SAbhishek Patel notifyAction = true; 1079017faf2SAbhishek Patel } 1089017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1099017faf2SAbhishek Patel { 1109017faf2SAbhishek Patel notifyAction = false; 1119017faf2SAbhishek Patel } 1129017faf2SAbhishek Patel 1139017faf2SAbhishek Patel return notifyAction; 1149017faf2SAbhishek Patel } 1159017faf2SAbhishek Patel 116*18f8f608SEd Tanous inline std::string getDumpPath(std::string_view dumpType) 117*18f8f608SEd Tanous { 118*18f8f608SEd Tanous std::string dbusDumpPath = "/xyz/openbmc_project/dump/"; 119*18f8f608SEd Tanous std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath), 120*18f8f608SEd Tanous bmcweb::asciiToLower); 121*18f8f608SEd Tanous 122*18f8f608SEd Tanous return dbusDumpPath; 123*18f8f608SEd Tanous } 124*18f8f608SEd Tanous 1257e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 12626ccae32SEd Tanous std::string_view field, 12739e77504SEd Tanous std::string_view& contents) 12816428a1aSJason M. Bills { 12916428a1aSJason M. Bills const char* data = nullptr; 13016428a1aSJason M. Bills size_t length = 0; 13116428a1aSJason M. Bills int ret = 0; 13216428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 13346ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 13446ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 13546ff87baSEd Tanous 13646ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 13716428a1aSJason M. Bills if (ret < 0) 13816428a1aSJason M. Bills { 13916428a1aSJason M. Bills return ret; 14016428a1aSJason M. Bills } 14139e77504SEd Tanous contents = std::string_view(data, length); 14216428a1aSJason M. Bills // Only use the content after the "=" character. 14381ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 14416428a1aSJason M. Bills return ret; 14516428a1aSJason M. Bills } 14616428a1aSJason M. Bills 1477e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 14826ccae32SEd Tanous std::string_view field, const int& base, 14926ccae32SEd Tanous long int& contents) 15016428a1aSJason M. Bills { 15116428a1aSJason M. Bills int ret = 0; 15239e77504SEd Tanous std::string_view metadata; 15316428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 15416428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 15516428a1aSJason M. Bills if (ret < 0) 15616428a1aSJason M. Bills { 15716428a1aSJason M. Bills return ret; 15816428a1aSJason M. Bills } 159b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 16016428a1aSJason M. Bills return ret; 16116428a1aSJason M. Bills } 16216428a1aSJason M. Bills 1637e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1647e860f15SJohn Edward Broadbent 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 1787e860f15SJohn Edward Broadbent inline static 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" 2717e860f15SJohn Edward Broadbent inline static bool 2728d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27375e8e218SMyung Bae const std::string& entryID, sd_id128_t& bootID, 27475e8e218SMyung Bae uint64_t& timestamp, uint64_t& index) 27516428a1aSJason M. Bills { 27616428a1aSJason M. Bills if (entryID.empty()) 27716428a1aSJason M. Bills { 27816428a1aSJason M. Bills return false; 27916428a1aSJason M. Bills } 28016428a1aSJason M. Bills 28175e8e218SMyung Bae // Convert the unique ID back to a bootID + timestamp to find the entry 28275e8e218SMyung Bae std::string_view entryIDStrView(entryID); 28375e8e218SMyung Bae auto underscore1Pos = entryIDStrView.find('_'); 28475e8e218SMyung Bae if (underscore1Pos == std::string_view::npos) 28575e8e218SMyung Bae { 28675e8e218SMyung Bae // EntryID has no bootID or timestamp 28775e8e218SMyung Bae messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 28875e8e218SMyung Bae return false; 28975e8e218SMyung Bae } 29075e8e218SMyung Bae 29175e8e218SMyung Bae // EntryID has bootID + timestamp 29275e8e218SMyung Bae 29375e8e218SMyung Bae // Convert entryIDViewString to BootID 29475e8e218SMyung Bae // NOTE: bootID string which needs to be null-terminated for 29575e8e218SMyung Bae // sd_id128_from_string() 29675e8e218SMyung Bae std::string bootIDStr(entryID, 0, underscore1Pos); 29775e8e218SMyung Bae if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0) 29875e8e218SMyung Bae { 29975e8e218SMyung Bae messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 30075e8e218SMyung Bae return false; 30175e8e218SMyung Bae } 30275e8e218SMyung Bae 30375e8e218SMyung Bae // Get the timestamp from entryID 30475e8e218SMyung Bae std::string_view timestampStrView = entryIDStrView; 30575e8e218SMyung Bae timestampStrView.remove_prefix(underscore1Pos + 1); 30675e8e218SMyung Bae 30775e8e218SMyung Bae // Check the index in timestamp 30875e8e218SMyung Bae auto underscore2Pos = timestampStrView.find('_'); 30975e8e218SMyung Bae if (underscore2Pos != std::string_view::npos) 31016428a1aSJason M. Bills { 31116428a1aSJason M. Bills // Timestamp has an index 31275e8e218SMyung Bae timestampStrView.remove_suffix(timestampStrView.size() - 31375e8e218SMyung Bae underscore2Pos); 31475e8e218SMyung Bae std::string_view indexStr(timestampStrView); 31575e8e218SMyung Bae indexStr.remove_prefix(underscore2Pos + 1); 31684396af9SPatrick Williams auto [ptr, ec] = std::from_chars(indexStr.begin(), indexStr.end(), 31784396af9SPatrick Williams index); 318c0bd5e4bSEd Tanous if (ec != std::errc()) 31916428a1aSJason M. Bills { 3209db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 32116428a1aSJason M. Bills return false; 32216428a1aSJason M. Bills } 32316428a1aSJason M. Bills } 32475e8e218SMyung Bae 32575e8e218SMyung Bae // Now timestamp has no index 32675e8e218SMyung Bae auto [ptr, ec] = std::from_chars(timestampStrView.begin(), 32775e8e218SMyung Bae timestampStrView.end(), timestamp); 328c0bd5e4bSEd Tanous if (ec != std::errc()) 32916428a1aSJason M. Bills { 3309db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 33116428a1aSJason M. Bills return false; 33216428a1aSJason M. Bills } 33316428a1aSJason M. Bills return true; 33416428a1aSJason M. Bills } 33516428a1aSJason M. Bills 33695820184SJason M. Bills static bool 33795820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 33895820184SJason M. Bills { 33995820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 34095820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 34195820184SJason M. Bills 34295820184SJason M. Bills // Loop through the directory looking for redfish log files 34395820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 34495820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 34595820184SJason M. Bills { 34695820184SJason M. Bills // If we find a redfish log file, save the path 34795820184SJason M. Bills std::string filename = dirEnt.path().filename(); 34811ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 34995820184SJason M. Bills { 35095820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 35195820184SJason M. Bills } 35295820184SJason M. Bills } 35395820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 35495820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 35595820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 3563544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 35795820184SJason M. Bills 35895820184SJason M. Bills return !redfishLogFiles.empty(); 35995820184SJason M. Bills } 36095820184SJason M. Bills 36168dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 36268dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 36368dd075aSAsmitha Karunanithi { 36468dd075aSAsmitha Karunanithi if (originatorType == 36568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 36668dd075aSAsmitha Karunanithi { 36768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 36868dd075aSAsmitha Karunanithi } 36968dd075aSAsmitha Karunanithi if (originatorType == 37068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 37168dd075aSAsmitha Karunanithi { 37268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 37368dd075aSAsmitha Karunanithi } 37468dd075aSAsmitha Karunanithi if (originatorType == 37568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 37668dd075aSAsmitha Karunanithi { 37768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 37868dd075aSAsmitha Karunanithi } 37968dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 38068dd075aSAsmitha Karunanithi } 38168dd075aSAsmitha Karunanithi 382aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3832d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 384c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 38568dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 386aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 387aefe3786SClaire Weinan { 388aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 389aefe3786SClaire Weinan { 390aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 391aefe3786SClaire Weinan { 392aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 393aefe3786SClaire Weinan { 394aefe3786SClaire Weinan if (propertyMap.first == "Status") 395aefe3786SClaire Weinan { 396aefe3786SClaire Weinan const auto* status = 397aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 398aefe3786SClaire Weinan if (status == nullptr) 399aefe3786SClaire Weinan { 400aefe3786SClaire Weinan messages::internalError(asyncResp->res); 401aefe3786SClaire Weinan break; 402aefe3786SClaire Weinan } 403aefe3786SClaire Weinan dumpStatus = *status; 404aefe3786SClaire Weinan } 405aefe3786SClaire Weinan } 406aefe3786SClaire Weinan } 407aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 408aefe3786SClaire Weinan { 409aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 410aefe3786SClaire Weinan { 411aefe3786SClaire Weinan if (propertyMap.first == "Size") 412aefe3786SClaire Weinan { 413aefe3786SClaire Weinan const auto* sizePtr = 414aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 415aefe3786SClaire Weinan if (sizePtr == nullptr) 416aefe3786SClaire Weinan { 417aefe3786SClaire Weinan messages::internalError(asyncResp->res); 418aefe3786SClaire Weinan break; 419aefe3786SClaire Weinan } 420aefe3786SClaire Weinan size = *sizePtr; 421aefe3786SClaire Weinan break; 422aefe3786SClaire Weinan } 423aefe3786SClaire Weinan } 424aefe3786SClaire Weinan } 425aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 426aefe3786SClaire Weinan { 427aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 428aefe3786SClaire Weinan { 429aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 430aefe3786SClaire Weinan { 431aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 432aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 433aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 434aefe3786SClaire Weinan { 435aefe3786SClaire Weinan messages::internalError(asyncResp->res); 436aefe3786SClaire Weinan break; 437aefe3786SClaire Weinan } 438c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 439aefe3786SClaire Weinan break; 440aefe3786SClaire Weinan } 441aefe3786SClaire Weinan } 442aefe3786SClaire Weinan } 44368dd075aSAsmitha Karunanithi else if (interfaceMap.first == 44468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 44568dd075aSAsmitha Karunanithi { 44668dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 44768dd075aSAsmitha Karunanithi { 44868dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 44968dd075aSAsmitha Karunanithi { 45068dd075aSAsmitha Karunanithi const std::string* id = 45168dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 45268dd075aSAsmitha Karunanithi if (id == nullptr) 45368dd075aSAsmitha Karunanithi { 45468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 45568dd075aSAsmitha Karunanithi break; 45668dd075aSAsmitha Karunanithi } 45768dd075aSAsmitha Karunanithi originatorId = *id; 45868dd075aSAsmitha Karunanithi } 45968dd075aSAsmitha Karunanithi 46068dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 46168dd075aSAsmitha Karunanithi { 46268dd075aSAsmitha Karunanithi const std::string* type = 46368dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 46468dd075aSAsmitha Karunanithi if (type == nullptr) 46568dd075aSAsmitha Karunanithi { 46668dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46768dd075aSAsmitha Karunanithi break; 46868dd075aSAsmitha Karunanithi } 46968dd075aSAsmitha Karunanithi 47068dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 47168dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 47268dd075aSAsmitha Karunanithi { 47368dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 47468dd075aSAsmitha Karunanithi break; 47568dd075aSAsmitha Karunanithi } 47668dd075aSAsmitha Karunanithi } 47768dd075aSAsmitha Karunanithi } 47868dd075aSAsmitha Karunanithi } 479aefe3786SClaire Weinan } 480aefe3786SClaire Weinan } 481aefe3786SClaire Weinan 48221ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 483fdd26906SClaire Weinan { 484fdd26906SClaire Weinan std::string entriesPath; 485fdd26906SClaire Weinan 486fdd26906SClaire Weinan if (dumpType == "BMC") 487fdd26906SClaire Weinan { 488fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 489fdd26906SClaire Weinan } 490fdd26906SClaire Weinan else if (dumpType == "FaultLog") 491fdd26906SClaire Weinan { 492fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 493fdd26906SClaire Weinan } 494fdd26906SClaire Weinan else if (dumpType == "System") 495fdd26906SClaire Weinan { 496fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 497fdd26906SClaire Weinan } 498fdd26906SClaire Weinan else 499fdd26906SClaire Weinan { 50062598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 50162598e31SEd Tanous dumpType); 502fdd26906SClaire Weinan } 503fdd26906SClaire Weinan 504fdd26906SClaire Weinan // Returns empty string on error 505fdd26906SClaire Weinan return entriesPath; 506fdd26906SClaire Weinan } 507fdd26906SClaire Weinan 5088d1b46d7Szhanghch05 inline void 5098d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5105cb1dd27SAsmitha Karunanithi const std::string& dumpType) 5115cb1dd27SAsmitha Karunanithi { 512fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 513fdd26906SClaire Weinan if (entriesPath.empty()) 5145cb1dd27SAsmitha Karunanithi { 5155cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5165cb1dd27SAsmitha Karunanithi return; 5175cb1dd27SAsmitha Karunanithi } 5185cb1dd27SAsmitha Karunanithi 5195eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5205eb468daSGeorge Liu dbus::utility::getManagedObjects( 5215eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 522fdd26906SClaire Weinan [asyncResp, entriesPath, 5235e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 5245eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 5255cb1dd27SAsmitha Karunanithi if (ec) 5265cb1dd27SAsmitha Karunanithi { 52762598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5285cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5295cb1dd27SAsmitha Karunanithi return; 5305cb1dd27SAsmitha Karunanithi } 5315cb1dd27SAsmitha Karunanithi 532fdd26906SClaire Weinan // Remove ending slash 533fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 534fdd26906SClaire Weinan if (!odataIdStr.empty()) 535fdd26906SClaire Weinan { 536fdd26906SClaire Weinan odataIdStr.pop_back(); 537fdd26906SClaire Weinan } 538fdd26906SClaire Weinan 539fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 540fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 541fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 542fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 54389492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 54489492a15SPatrick Williams " Dump Entries"; 545fdd26906SClaire Weinan 5463544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 547*18f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 5485cb1dd27SAsmitha Karunanithi 5495eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 5503544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 551002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 552002d39b4SEd Tanous r.first.filename()); 553565dfb6fSClaire Weinan }); 554565dfb6fSClaire Weinan 5555cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5565cb1dd27SAsmitha Karunanithi { 557b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5585cb1dd27SAsmitha Karunanithi { 5595cb1dd27SAsmitha Karunanithi continue; 5605cb1dd27SAsmitha Karunanithi } 561c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5625cb1dd27SAsmitha Karunanithi uint64_t size = 0; 56335440d18SAsmitha Karunanithi std::string dumpStatus; 56468dd075aSAsmitha Karunanithi std::string originatorId; 56568dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 56668dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 567433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5682dfd18efSEd Tanous 5692dfd18efSEd Tanous std::string entryID = object.first.filename(); 5702dfd18efSEd Tanous if (entryID.empty()) 5715cb1dd27SAsmitha Karunanithi { 5725cb1dd27SAsmitha Karunanithi continue; 5735cb1dd27SAsmitha Karunanithi } 5745cb1dd27SAsmitha Karunanithi 575c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 57668dd075aSAsmitha Karunanithi originatorId, originatorType, 577aefe3786SClaire Weinan asyncResp); 5785cb1dd27SAsmitha Karunanithi 5790fda0f12SGeorge Liu if (dumpStatus != 5800fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 58135440d18SAsmitha Karunanithi !dumpStatus.empty()) 58235440d18SAsmitha Karunanithi { 58335440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 58435440d18SAsmitha Karunanithi continue; 58535440d18SAsmitha Karunanithi } 58635440d18SAsmitha Karunanithi 58768dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 588fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5895cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5905cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5915cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 592bbd80db8SClaire Weinan thisEntry["Created"] = 593bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5945cb1dd27SAsmitha Karunanithi 59568dd075aSAsmitha Karunanithi if (!originatorId.empty()) 59668dd075aSAsmitha Karunanithi { 59768dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 59868dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 59968dd075aSAsmitha Karunanithi } 60068dd075aSAsmitha Karunanithi 6015cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6025cb1dd27SAsmitha Karunanithi { 603d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 60489492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 60589492a15SPatrick Williams "/attachment"; 606fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6075cb1dd27SAsmitha Karunanithi } 6085cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6095cb1dd27SAsmitha Karunanithi { 610d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 611d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 61289492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 61389492a15SPatrick Williams "/attachment"; 614fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6155cb1dd27SAsmitha Karunanithi } 616b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 6175cb1dd27SAsmitha Karunanithi } 618002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 6193544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 6205eb468daSGeorge Liu }); 6215cb1dd27SAsmitha Karunanithi } 6225cb1dd27SAsmitha Karunanithi 6238d1b46d7Szhanghch05 inline void 624c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6258d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 6265cb1dd27SAsmitha Karunanithi { 627fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 628fdd26906SClaire Weinan if (entriesPath.empty()) 6295cb1dd27SAsmitha Karunanithi { 6305cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6315cb1dd27SAsmitha Karunanithi return; 6325cb1dd27SAsmitha Karunanithi } 6335cb1dd27SAsmitha Karunanithi 6345eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 6355eb468daSGeorge Liu dbus::utility::getManagedObjects( 6365eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 637fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 6385e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 63902cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 6405cb1dd27SAsmitha Karunanithi if (ec) 6415cb1dd27SAsmitha Karunanithi { 64262598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 6435cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6445cb1dd27SAsmitha Karunanithi return; 6455cb1dd27SAsmitha Karunanithi } 6465cb1dd27SAsmitha Karunanithi 647b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 648*18f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 649b47452b2SAsmitha Karunanithi 6509eb808c1SEd Tanous for (const auto& objectPath : resp) 6515cb1dd27SAsmitha Karunanithi { 652b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6535cb1dd27SAsmitha Karunanithi { 6545cb1dd27SAsmitha Karunanithi continue; 6555cb1dd27SAsmitha Karunanithi } 6565cb1dd27SAsmitha Karunanithi 6575cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 658c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6595cb1dd27SAsmitha Karunanithi uint64_t size = 0; 66035440d18SAsmitha Karunanithi std::string dumpStatus; 66168dd075aSAsmitha Karunanithi std::string originatorId; 66268dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 66368dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6645cb1dd27SAsmitha Karunanithi 665aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 66668dd075aSAsmitha Karunanithi timestampUs, originatorId, 66768dd075aSAsmitha Karunanithi originatorType, asyncResp); 6685cb1dd27SAsmitha Karunanithi 6690fda0f12SGeorge Liu if (dumpStatus != 6700fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 67135440d18SAsmitha Karunanithi !dumpStatus.empty()) 67235440d18SAsmitha Karunanithi { 67335440d18SAsmitha Karunanithi // Dump status is not Complete 67435440d18SAsmitha Karunanithi // return not found until status is changed to Completed 675d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 676d1bde9e5SKrzysztof Grobelny entryID); 67735440d18SAsmitha Karunanithi return; 67835440d18SAsmitha Karunanithi } 67935440d18SAsmitha Karunanithi 6805cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 68168dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 682fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6835cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6845cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6855cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 686bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 687bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6885cb1dd27SAsmitha Karunanithi 68968dd075aSAsmitha Karunanithi if (!originatorId.empty()) 69068dd075aSAsmitha Karunanithi { 69168dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 69268dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 69368dd075aSAsmitha Karunanithi } 69468dd075aSAsmitha Karunanithi 6955cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6965cb1dd27SAsmitha Karunanithi { 697d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 698d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 699fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 700fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7015cb1dd27SAsmitha Karunanithi } 7025cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 7035cb1dd27SAsmitha Karunanithi { 704d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 705002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 706d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 707fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 708fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7095cb1dd27SAsmitha Karunanithi } 7105cb1dd27SAsmitha Karunanithi } 711e05aec50SEd Tanous if (!foundDumpEntry) 712b47452b2SAsmitha Karunanithi { 71362598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 714b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 715b90d14f2SMyung Bae entryID); 716b47452b2SAsmitha Karunanithi return; 717b47452b2SAsmitha Karunanithi } 7185eb468daSGeorge Liu }); 7195cb1dd27SAsmitha Karunanithi } 7205cb1dd27SAsmitha Karunanithi 7218d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7229878256fSStanley Chu const std::string& entryID, 723b47452b2SAsmitha Karunanithi const std::string& dumpType) 7245cb1dd27SAsmitha Karunanithi { 7255a39f77aSPatrick Williams auto respHandler = [asyncResp, 7265a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 72762598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 7285cb1dd27SAsmitha Karunanithi if (ec) 7295cb1dd27SAsmitha Karunanithi { 7303de8d8baSGeorge Liu if (ec.value() == EBADR) 7313de8d8baSGeorge Liu { 7323de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 7333de8d8baSGeorge Liu return; 7343de8d8baSGeorge Liu } 73562598e31SEd Tanous BMCWEB_LOG_ERROR( 73662598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 73762598e31SEd Tanous entryID); 7385cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 7395cb1dd27SAsmitha Karunanithi return; 7405cb1dd27SAsmitha Karunanithi } 7415cb1dd27SAsmitha Karunanithi }; 742*18f8f608SEd Tanous 7435cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7445cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 745*18f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 7465cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7475cb1dd27SAsmitha Karunanithi } 7485cb1dd27SAsmitha Karunanithi 749168d1b1aSCarson Labrado inline void 750168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 751168d1b1aSCarson Labrado const std::string& entryID, 752168d1b1aSCarson Labrado const std::string& downloadEntryType, 753168d1b1aSCarson Labrado const boost::system::error_code& ec, 754168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 755168d1b1aSCarson Labrado { 756168d1b1aSCarson Labrado if (ec.value() == EBADR) 757168d1b1aSCarson Labrado { 758168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 759168d1b1aSCarson Labrado return; 760168d1b1aSCarson Labrado } 761168d1b1aSCarson Labrado if (ec) 762168d1b1aSCarson Labrado { 763168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 764168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 765168d1b1aSCarson Labrado return; 766168d1b1aSCarson Labrado } 767168d1b1aSCarson Labrado 768168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 769168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 770168d1b1aSCarson Labrado { 771168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 772168d1b1aSCarson Labrado downloadEntryType); 773168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 774168d1b1aSCarson Labrado } 775168d1b1aSCarson Labrado 776168d1b1aSCarson Labrado int fd = -1; 777168d1b1aSCarson Labrado fd = dup(unixfd); 778168d1b1aSCarson Labrado if (fd < 0) 779168d1b1aSCarson Labrado { 780168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 781168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 782168d1b1aSCarson Labrado return; 783168d1b1aSCarson Labrado } 784168d1b1aSCarson Labrado 785168d1b1aSCarson Labrado long long int size = lseek(fd, 0, SEEK_END); 786168d1b1aSCarson Labrado if (size <= 0) 787168d1b1aSCarson Labrado { 788168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 789168d1b1aSCarson Labrado size); 790168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 791168d1b1aSCarson Labrado close(fd); 792168d1b1aSCarson Labrado return; 793168d1b1aSCarson Labrado } 794168d1b1aSCarson Labrado 795168d1b1aSCarson Labrado // Arbitrary max size of 20MB to accommodate BMC dumps 796168d1b1aSCarson Labrado constexpr int maxFileSize = 20 * 1024 * 1024; 797168d1b1aSCarson Labrado if (size > maxFileSize) 798168d1b1aSCarson Labrado { 799168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 800168d1b1aSCarson Labrado size, maxFileSize); 801168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 802168d1b1aSCarson Labrado close(fd); 803168d1b1aSCarson Labrado return; 804168d1b1aSCarson Labrado } 805168d1b1aSCarson Labrado long long int rc = lseek(fd, 0, SEEK_SET); 806168d1b1aSCarson Labrado if (rc < 0) 807168d1b1aSCarson Labrado { 808168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 809168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 810168d1b1aSCarson Labrado close(fd); 811168d1b1aSCarson Labrado return; 812168d1b1aSCarson Labrado } 813168d1b1aSCarson Labrado 81427b0cf90SEd Tanous std::string body; 81527b0cf90SEd Tanous body.resize(static_cast<size_t>(size), '\0'); 81627b0cf90SEd Tanous rc = read(fd, body.data(), body.size()); 817168d1b1aSCarson Labrado if ((rc == -1) || (rc != size)) 818168d1b1aSCarson Labrado { 819168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to read in file"); 820168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 821168d1b1aSCarson Labrado close(fd); 822168d1b1aSCarson Labrado return; 823168d1b1aSCarson Labrado } 824168d1b1aSCarson Labrado close(fd); 825168d1b1aSCarson Labrado if (downloadEntryType == "System") 826168d1b1aSCarson Labrado { 82727b0cf90SEd Tanous // Base64 encode response. 82827b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(body)); 829168d1b1aSCarson Labrado asyncResp->res.addHeader( 830168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 831168d1b1aSCarson Labrado } 83227b0cf90SEd Tanous else 83327b0cf90SEd Tanous { 83427b0cf90SEd Tanous asyncResp->res.write(std::move(body)); 83527b0cf90SEd Tanous } 836168d1b1aSCarson Labrado 837168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 838168d1b1aSCarson Labrado "application/octet-stream"); 839168d1b1aSCarson Labrado } 840168d1b1aSCarson Labrado 841168d1b1aSCarson Labrado inline void 842168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 843168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 844168d1b1aSCarson Labrado { 845168d1b1aSCarson Labrado if (dumpType != "BMC") 846168d1b1aSCarson Labrado { 847168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 848168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 849168d1b1aSCarson Labrado return; 850168d1b1aSCarson Labrado } 851168d1b1aSCarson Labrado 852*18f8f608SEd Tanous std::string dumpEntryPath = std::format("{}/entry/{}", 853*18f8f608SEd Tanous getDumpPath(dumpType), entryID); 854168d1b1aSCarson Labrado 855168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 856168d1b1aSCarson Labrado [asyncResp, entryID, 857168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 858168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 859168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 860168d1b1aSCarson Labrado }; 861168d1b1aSCarson Labrado 862168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 863168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 864168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 865168d1b1aSCarson Labrado } 866168d1b1aSCarson Labrado 867168d1b1aSCarson Labrado inline void 868168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 869168d1b1aSCarson Labrado const std::string& systemName, 870168d1b1aSCarson Labrado const std::string& entryID, 871168d1b1aSCarson Labrado const std::string& dumpType) 872168d1b1aSCarson Labrado { 873168d1b1aSCarson Labrado if constexpr (bmcwebEnableMultiHost) 874168d1b1aSCarson Labrado { 875168d1b1aSCarson Labrado // Option currently returns no systems. TBD 876168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 877168d1b1aSCarson Labrado systemName); 878168d1b1aSCarson Labrado return; 879168d1b1aSCarson Labrado } 880168d1b1aSCarson Labrado if (systemName != "system") 881168d1b1aSCarson Labrado { 882168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 883168d1b1aSCarson Labrado systemName); 884168d1b1aSCarson Labrado return; 885168d1b1aSCarson Labrado } 886168d1b1aSCarson Labrado 887168d1b1aSCarson Labrado std::string entryPath = 888168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 889168d1b1aSCarson Labrado entryID; 890168d1b1aSCarson Labrado 891168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 892168d1b1aSCarson Labrado [asyncResp, entryID, 893168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 894168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 895168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 896168d1b1aSCarson Labrado }; 897168d1b1aSCarson Labrado 898168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 899168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 900168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 901168d1b1aSCarson Labrado } 902168d1b1aSCarson Labrado 9038e31778eSAsmitha Karunanithi inline DumpCreationProgress 9048e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 905a43be80fSAsmitha Karunanithi { 9068e31778eSAsmitha Karunanithi if (status == 9078e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 9088e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 9098e31778eSAsmitha Karunanithi { 9108e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9118e31778eSAsmitha Karunanithi } 9128e31778eSAsmitha Karunanithi if (status == 9138e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 9148e31778eSAsmitha Karunanithi { 9158e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 9168e31778eSAsmitha Karunanithi } 9178e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9188e31778eSAsmitha Karunanithi } 9198e31778eSAsmitha Karunanithi 9208e31778eSAsmitha Karunanithi inline DumpCreationProgress 9218e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 9228e31778eSAsmitha Karunanithi { 9238e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 9248e31778eSAsmitha Karunanithi { 9258e31778eSAsmitha Karunanithi if (key == "Status") 9268e31778eSAsmitha Karunanithi { 9278e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 9288e31778eSAsmitha Karunanithi if (value == nullptr) 9298e31778eSAsmitha Karunanithi { 93062598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 9318e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9328e31778eSAsmitha Karunanithi } 9338e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 9348e31778eSAsmitha Karunanithi } 9358e31778eSAsmitha Karunanithi } 9368e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9378e31778eSAsmitha Karunanithi } 9388e31778eSAsmitha Karunanithi 9398e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 9408e31778eSAsmitha Karunanithi { 9418e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 9428e31778eSAsmitha Karunanithi { 9438e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 9448e31778eSAsmitha Karunanithi } 9458e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 9468e31778eSAsmitha Karunanithi { 9478e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 9488e31778eSAsmitha Karunanithi } 9498e31778eSAsmitha Karunanithi return ""; 9508e31778eSAsmitha Karunanithi } 9518e31778eSAsmitha Karunanithi 9528e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 9538e31778eSAsmitha Karunanithi task::Payload&& payload, 9548e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9558e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 9568e31778eSAsmitha Karunanithi { 9578e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 9588e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 9598e31778eSAsmitha Karunanithi 9608e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 9618e31778eSAsmitha Karunanithi 9628e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 9638e31778eSAsmitha Karunanithi { 96462598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 9658e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9668e31778eSAsmitha Karunanithi return; 9678e31778eSAsmitha Karunanithi } 9688e31778eSAsmitha Karunanithi 9698e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9708e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 9718e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 9725e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 9738e31778eSAsmitha Karunanithi const std::string& introspectXml) { 9748e31778eSAsmitha Karunanithi if (ec) 9758e31778eSAsmitha Karunanithi { 97662598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 97762598e31SEd Tanous ec.message()); 9788e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9798e31778eSAsmitha Karunanithi return; 9808e31778eSAsmitha Karunanithi } 9818e31778eSAsmitha Karunanithi 9828e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 9838e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 9848e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 9858e31778eSAsmitha Karunanithi // Else, return task completed. 9868e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 9878e31778eSAsmitha Karunanithi 9888e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 9898e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 9908e31778eSAsmitha Karunanithi if (pRoot == nullptr) 9918e31778eSAsmitha Karunanithi { 99262598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 9938e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9948e31778eSAsmitha Karunanithi return; 9958e31778eSAsmitha Karunanithi } 9968e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 9978e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 9988e31778eSAsmitha Karunanithi 9998e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 10008e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 10018e31778eSAsmitha Karunanithi { 10028e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 10038e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 10048e31778eSAsmitha Karunanithi { 10058e31778eSAsmitha Karunanithi if (thisInterfaceName == 10068e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 10078e31778eSAsmitha Karunanithi { 10088e31778eSAsmitha Karunanithi interfaceNode = 10098e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 10108e31778eSAsmitha Karunanithi continue; 10118e31778eSAsmitha Karunanithi } 10128e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 10138e31778eSAsmitha Karunanithi break; 10148e31778eSAsmitha Karunanithi } 10158e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 10168e31778eSAsmitha Karunanithi } 10178e31778eSAsmitha Karunanithi 1018a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 10198e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 10208b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 1021a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 10228b24275dSEd Tanous if (ec2) 1023cb13a392SEd Tanous { 102462598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 102562598e31SEd Tanous createdObjPath.str); 10268e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 10276145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 10286145ed6fSAsmitha Karunanithi return task::completed; 1029cb13a392SEd Tanous } 1030b9d36b47SEd Tanous 10318e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 1032a43be80fSAsmitha Karunanithi { 10338e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 10348e31778eSAsmitha Karunanithi std::string prop; 10358e31778eSAsmitha Karunanithi msg.read(prop, values); 10368e31778eSAsmitha Karunanithi 10378e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 10388e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 10398e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 10408e31778eSAsmitha Karunanithi { 104162598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 104262598e31SEd Tanous createdObjPath.str); 10438e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 10448e31778eSAsmitha Karunanithi return task::completed; 10458e31778eSAsmitha Karunanithi } 10468e31778eSAsmitha Karunanithi 10478e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 10488e31778eSAsmitha Karunanithi { 104962598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 105062598e31SEd Tanous createdObjPath.str); 10518e31778eSAsmitha Karunanithi return !task::completed; 10528e31778eSAsmitha Karunanithi } 10538e31778eSAsmitha Karunanithi } 10548e31778eSAsmitha Karunanithi 1055a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 1056a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 1057a43be80fSAsmitha Karunanithi 1058c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 1059c51a58eeSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId); 1060c51a58eeSEd Tanous 1061c51a58eeSEd Tanous std::string headerLoc = "Location: "; 1062c51a58eeSEd Tanous headerLoc += url.buffer(); 1063c51a58eeSEd Tanous 1064002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 1065a43be80fSAsmitha Karunanithi 106662598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 106762598e31SEd Tanous createdObjPath.str); 1068a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 1069b47452b2SAsmitha Karunanithi return task::completed; 1070a43be80fSAsmitha Karunanithi }, 10718e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 10728e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 10738e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 1074a43be80fSAsmitha Karunanithi 10758e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 10768e31778eSAsmitha Karunanithi // requested dump will be collected. 10778e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 1078a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 10798e31778eSAsmitha Karunanithi task->payload.emplace(payload); 10808e31778eSAsmitha Karunanithi }, 10818e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 10828e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 1083a43be80fSAsmitha Karunanithi } 1084a43be80fSAsmitha Karunanithi 10858d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10868d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 1087a43be80fSAsmitha Karunanithi { 1088fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 1089fdd26906SClaire Weinan if (dumpPath.empty()) 1090a43be80fSAsmitha Karunanithi { 1091a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1092a43be80fSAsmitha Karunanithi return; 1093a43be80fSAsmitha Karunanithi } 1094a43be80fSAsmitha Karunanithi 1095a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 1096a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 1097a43be80fSAsmitha Karunanithi 109815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 1099a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 1100a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 1101a43be80fSAsmitha Karunanithi { 1102a43be80fSAsmitha Karunanithi return; 1103a43be80fSAsmitha Karunanithi } 1104a43be80fSAsmitha Karunanithi 1105a43be80fSAsmitha Karunanithi if (dumpType == "System") 1106a43be80fSAsmitha Karunanithi { 1107a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 1108a43be80fSAsmitha Karunanithi { 110962598e31SEd Tanous BMCWEB_LOG_ERROR( 111062598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 1111a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1112a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 1113a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 1114a43be80fSAsmitha Karunanithi return; 1115a43be80fSAsmitha Karunanithi } 11163174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 1117a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 1118a43be80fSAsmitha Karunanithi { 111962598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 1120ace85d60SEd Tanous messages::internalError(asyncResp->res); 1121a43be80fSAsmitha Karunanithi return; 1122a43be80fSAsmitha Karunanithi } 11235907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 1124a43be80fSAsmitha Karunanithi } 1125a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 1126a43be80fSAsmitha Karunanithi { 1127a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 1128a43be80fSAsmitha Karunanithi { 112962598e31SEd Tanous BMCWEB_LOG_ERROR( 113062598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 1131a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1132a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 1133a43be80fSAsmitha Karunanithi return; 1134a43be80fSAsmitha Karunanithi } 11353174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 1136a43be80fSAsmitha Karunanithi { 113762598e31SEd Tanous BMCWEB_LOG_ERROR( 113862598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 1139ace85d60SEd Tanous messages::internalError(asyncResp->res); 1140a43be80fSAsmitha Karunanithi return; 1141a43be80fSAsmitha Karunanithi } 11425907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 11435907571dSAsmitha Karunanithi } 11445907571dSAsmitha Karunanithi else 11455907571dSAsmitha Karunanithi { 114662598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 11475907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11485907571dSAsmitha Karunanithi return; 1149a43be80fSAsmitha Karunanithi } 1150a43be80fSAsmitha Karunanithi 11518e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 11528e31778eSAsmitha Karunanithi createDumpParamVec; 11538e31778eSAsmitha Karunanithi 1154f574a8e1SCarson Labrado if (req.session != nullptr) 1155f574a8e1SCarson Labrado { 115668dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 115768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 115868dd075aSAsmitha Karunanithi req.session->clientIp); 115968dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 116068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 116168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1162f574a8e1SCarson Labrado } 116368dd075aSAsmitha Karunanithi 1164a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 11655e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 11665e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 11675e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 11688e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1169a43be80fSAsmitha Karunanithi if (ec) 1170a43be80fSAsmitha Karunanithi { 117162598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 11725907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 11735907571dSAsmitha Karunanithi if (dbusError == nullptr) 11745907571dSAsmitha Karunanithi { 11755907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11765907571dSAsmitha Karunanithi return; 11775907571dSAsmitha Karunanithi } 11785907571dSAsmitha Karunanithi 117962598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 118062598e31SEd Tanous dbusError->name, dbusError->message); 11815907571dSAsmitha Karunanithi if (std::string_view( 11825907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 11835907571dSAsmitha Karunanithi dbusError->name) 11845907571dSAsmitha Karunanithi { 11855907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 11865907571dSAsmitha Karunanithi return; 11875907571dSAsmitha Karunanithi } 11885907571dSAsmitha Karunanithi if (std::string_view( 11895907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 11905907571dSAsmitha Karunanithi dbusError->name) 11915907571dSAsmitha Karunanithi { 11925907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 11935907571dSAsmitha Karunanithi return; 11945907571dSAsmitha Karunanithi } 11955907571dSAsmitha Karunanithi if (std::string_view( 11965907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 11975907571dSAsmitha Karunanithi dbusError->name) 11985907571dSAsmitha Karunanithi { 11995907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 12005907571dSAsmitha Karunanithi return; 12015907571dSAsmitha Karunanithi } 12025907571dSAsmitha Karunanithi // Other Dbus errors such as: 12035907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 12045907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 12055907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 12065907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 12075907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 12085907571dSAsmitha Karunanithi // back to the client. 1209a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1210a43be80fSAsmitha Karunanithi return; 1211a43be80fSAsmitha Karunanithi } 121262598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 12138e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1214a43be80fSAsmitha Karunanithi }, 1215*18f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12168e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1217a43be80fSAsmitha Karunanithi } 1218a43be80fSAsmitha Karunanithi 12198d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12208d1b46d7Szhanghch05 const std::string& dumpType) 122180319af1SAsmitha Karunanithi { 12220d946211SClaire Weinan crow::connections::systemBus->async_method_call( 12230d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 122480319af1SAsmitha Karunanithi if (ec) 122580319af1SAsmitha Karunanithi { 122662598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 122780319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 122880319af1SAsmitha Karunanithi return; 122980319af1SAsmitha Karunanithi } 12300d946211SClaire Weinan }, 1231*18f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12320d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 123380319af1SAsmitha Karunanithi } 123480319af1SAsmitha Karunanithi 1235b9d36b47SEd Tanous inline static void 1236b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1237b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1238b9d36b47SEd Tanous std::string& logfile) 1239043a0536SJohnathan Mantey { 1240d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1241d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1242d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1243d1bde9e5SKrzysztof Grobelny 1244d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1245d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1246d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1247d1bde9e5SKrzysztof Grobelny 1248d1bde9e5SKrzysztof Grobelny if (!success) 1249043a0536SJohnathan Mantey { 1250d1bde9e5SKrzysztof Grobelny return; 1251043a0536SJohnathan Mantey } 1252d1bde9e5SKrzysztof Grobelny 1253d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1254043a0536SJohnathan Mantey { 1255d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1256d1bde9e5SKrzysztof Grobelny } 1257d1bde9e5SKrzysztof Grobelny 1258d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1259043a0536SJohnathan Mantey { 1260d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1261043a0536SJohnathan Mantey } 1262d1bde9e5SKrzysztof Grobelny 1263d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1264043a0536SJohnathan Mantey { 1265d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1266043a0536SJohnathan Mantey } 1267043a0536SJohnathan Mantey } 1268043a0536SJohnathan Mantey 12697e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 12701da66f75SEd Tanous { 1271c4bf6374SJason M. Bills /** 1272c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1273c4bf6374SJason M. Bills */ 127422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1275ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1276002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1277002d39b4SEd Tanous [&app](const crow::Request& req, 127822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 127922d268cbSEd Tanous const std::string& systemName) { 12803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1281c4bf6374SJason M. Bills { 128245ca1b86SEd Tanous return; 128345ca1b86SEd Tanous } 12847f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 12857f3e84a1SEd Tanous { 12867f3e84a1SEd Tanous // Option currently returns no systems. TBD 12877f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 12887f3e84a1SEd Tanous systemName); 12897f3e84a1SEd Tanous return; 12907f3e84a1SEd Tanous } 129122d268cbSEd Tanous if (systemName != "system") 129222d268cbSEd Tanous { 129322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 129422d268cbSEd Tanous systemName); 129522d268cbSEd Tanous return; 129622d268cbSEd Tanous } 129722d268cbSEd Tanous 12987e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 12997e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1300c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1301c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1302c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1303029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 130445ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1305c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1306c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1307002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1308c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 13091476687dSEd Tanous nlohmann::json::object_t eventLog; 13101476687dSEd Tanous eventLog["@odata.id"] = 13111476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1312b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 13135cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 13141476687dSEd Tanous nlohmann::json::object_t dumpLog; 1315002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1316b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1317c9bb6861Sraviteja-b #endif 1318c9bb6861Sraviteja-b 1319d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 13201476687dSEd Tanous nlohmann::json::object_t crashdump; 13211476687dSEd Tanous crashdump["@odata.id"] = 13221476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1323b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1324d53dd41fSJason M. Bills #endif 1325b7028ebfSSpencer Ku 1326b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 13271476687dSEd Tanous nlohmann::json::object_t hostlogger; 13281476687dSEd Tanous hostlogger["@odata.id"] = 13291476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1330b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1331b7028ebfSSpencer Ku #endif 1332c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1333c4bf6374SJason M. Bills logServiceArray.size(); 1334a3316fc6SZhikuiRen 13357a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 13367a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 13377a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 13387a1dbc48SGeorge Liu "/", 0, interfaces, 13397a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1340b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1341b9d36b47SEd Tanous subtreePath) { 1342a3316fc6SZhikuiRen if (ec) 1343a3316fc6SZhikuiRen { 134462598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1345a3316fc6SZhikuiRen return; 1346a3316fc6SZhikuiRen } 1347a3316fc6SZhikuiRen 134855f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1349a3316fc6SZhikuiRen { 1350a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1351a3316fc6SZhikuiRen { 135223a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1353a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1354613dabeaSEd Tanous nlohmann::json::object_t member; 1355613dabeaSEd Tanous member["@odata.id"] = 1356613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1357613dabeaSEd Tanous 1358b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1359613dabeaSEd Tanous 136045ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 136123a21a1cSEd Tanous logServiceArrayLocal.size(); 1362a3316fc6SZhikuiRen return; 1363a3316fc6SZhikuiRen } 1364a3316fc6SZhikuiRen } 13657a1dbc48SGeorge Liu }); 13667e860f15SJohn Edward Broadbent }); 1367c4bf6374SJason M. Bills } 1368c4bf6374SJason M. Bills 13697e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1370c4bf6374SJason M. Bills { 137122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1372ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1373002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1374002d39b4SEd Tanous [&app](const crow::Request& req, 137522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 137622d268cbSEd Tanous const std::string& systemName) { 13773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 137845ca1b86SEd Tanous { 137945ca1b86SEd Tanous return; 138045ca1b86SEd Tanous } 138122d268cbSEd Tanous if (systemName != "system") 138222d268cbSEd Tanous { 138322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 138422d268cbSEd Tanous systemName); 138522d268cbSEd Tanous return; 138622d268cbSEd Tanous } 1387c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1388029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1389c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1390b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1391c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1392002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1393c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1394c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 13957c8c4058STejas Patil 13967c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 13972b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 13987c8c4058STejas Patil 13997c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 14007c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 14017c8c4058STejas Patil redfishDateTimeOffset.second; 14027c8c4058STejas Patil 14031476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 14041476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1405e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1406e7d6c8b2SGunnar Mills 14070fda0f12SGeorge Liu {"target", 14080fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 14097e860f15SJohn Edward Broadbent }); 1410489640c6SJason M. Bills } 1411489640c6SJason M. Bills 14127e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1413489640c6SJason M. Bills { 14144978b63fSJason M. Bills BMCWEB_ROUTE( 14154978b63fSJason M. Bills app, 141622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1417432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 14187e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 141945ca1b86SEd Tanous [&app](const crow::Request& req, 142022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 142122d268cbSEd Tanous const std::string& systemName) { 14223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 142345ca1b86SEd Tanous { 142445ca1b86SEd Tanous return; 142545ca1b86SEd Tanous } 142622d268cbSEd Tanous if (systemName != "system") 142722d268cbSEd Tanous { 142822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 142922d268cbSEd Tanous systemName); 143022d268cbSEd Tanous return; 143122d268cbSEd Tanous } 1432489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1433489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1434489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1435489640c6SJason M. Bills { 1436489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1437489640c6SJason M. Bills { 1438489640c6SJason M. Bills std::error_code ec; 1439489640c6SJason M. Bills std::filesystem::remove(file, ec); 1440489640c6SJason M. Bills } 1441489640c6SJason M. Bills } 1442489640c6SJason M. Bills 1443489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1444489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 14455e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1446489640c6SJason M. Bills if (ec) 1447489640c6SJason M. Bills { 144862598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1449489640c6SJason M. Bills messages::internalError(asyncResp->res); 1450489640c6SJason M. Bills return; 1451489640c6SJason M. Bills } 1452489640c6SJason M. Bills 1453489640c6SJason M. Bills messages::success(asyncResp->res); 1454489640c6SJason M. Bills }, 1455489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1456002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1457002d39b4SEd Tanous "replace"); 14587e860f15SJohn Edward Broadbent }); 1459c4bf6374SJason M. Bills } 1460c4bf6374SJason M. Bills 1461ac992cdeSJason M. Bills enum class LogParseError 1462ac992cdeSJason M. Bills { 1463ac992cdeSJason M. Bills success, 1464ac992cdeSJason M. Bills parseFailed, 1465ac992cdeSJason M. Bills messageIdNotInRegistry, 1466ac992cdeSJason M. Bills }; 1467ac992cdeSJason M. Bills 1468ac992cdeSJason M. Bills static LogParseError 1469ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1470b5a76932SEd Tanous const std::string& logEntry, 1471de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1472c4bf6374SJason M. Bills { 147395820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1474cd225da8SJason M. Bills // First get the Timestamp 1475f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1476cd225da8SJason M. Bills if (space == std::string::npos) 147795820184SJason M. Bills { 1478ac992cdeSJason M. Bills return LogParseError::parseFailed; 147995820184SJason M. Bills } 1480cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1481cd225da8SJason M. Bills // Then get the log contents 1482f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1483cd225da8SJason M. Bills if (entryStart == std::string::npos) 1484cd225da8SJason M. Bills { 1485ac992cdeSJason M. Bills return LogParseError::parseFailed; 1486cd225da8SJason M. Bills } 1487cd225da8SJason M. Bills std::string_view entry(logEntry); 1488cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1489cd225da8SJason M. Bills // Use split to separate the entry into its fields 1490cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 149150ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1492cd225da8SJason M. Bills // We need at least a MessageId to be valid 14931e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 14941e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1495cd225da8SJason M. Bills { 1496ac992cdeSJason M. Bills return LogParseError::parseFailed; 1497cd225da8SJason M. Bills } 14981e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 14994851d45dSJason M. Bills // Get the Message from the MessageRegistry 1500fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1501c4bf6374SJason M. Bills 15021e6deaf6SEd Tanous logEntryIter++; 150354417b02SSui Chen if (message == nullptr) 1504c4bf6374SJason M. Bills { 150562598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1506ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1507c4bf6374SJason M. Bills } 1508c4bf6374SJason M. Bills 15091e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 15101e6deaf6SEd Tanous logEntryFields.end()); 1511c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1512c05bba45SEd Tanous 15131e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 15141e6deaf6SEd Tanous message->message); 15151e6deaf6SEd Tanous if (msg.empty()) 151615a86ff6SJason M. Bills { 15171e6deaf6SEd Tanous return LogParseError::parseFailed; 151815a86ff6SJason M. Bills } 15194851d45dSJason M. Bills 152095820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 152195820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 152295820184SJason M. Bills // between the '.' and the '+', so just remove them. 1523f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1524f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 152595820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1526c4bf6374SJason M. Bills { 152795820184SJason M. Bills timestamp.erase(dot, plus - dot); 1528c4bf6374SJason M. Bills } 1529c4bf6374SJason M. Bills 1530c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 15319c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1532ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1533ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1534ef4c65b7SEd Tanous logEntryID); 153584afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 153684afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 153784afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 153884afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 153984afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 154084afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 154184afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 154284afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1543ac992cdeSJason M. Bills return LogParseError::success; 1544c4bf6374SJason M. Bills } 1545c4bf6374SJason M. Bills 15467e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1547c4bf6374SJason M. Bills { 154822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 15498b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1550002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1551002d39b4SEd Tanous [&app](const crow::Request& req, 155222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 155322d268cbSEd Tanous const std::string& systemName) { 1554c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1555c937d2bfSEd Tanous .canDelegateTop = true, 1556c937d2bfSEd Tanous .canDelegateSkip = true, 1557c937d2bfSEd Tanous }; 1558c937d2bfSEd Tanous query_param::Query delegatedQuery; 1559c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 15603ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1561c4bf6374SJason M. Bills { 1562c4bf6374SJason M. Bills return; 1563c4bf6374SJason M. Bills } 15647f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 15657f3e84a1SEd Tanous { 15667f3e84a1SEd Tanous // Option currently returns no systems. TBD 15677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15687f3e84a1SEd Tanous systemName); 15697f3e84a1SEd Tanous return; 15707f3e84a1SEd Tanous } 157122d268cbSEd Tanous if (systemName != "system") 157222d268cbSEd Tanous { 157322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 157422d268cbSEd Tanous systemName); 157522d268cbSEd Tanous return; 157622d268cbSEd Tanous } 157722d268cbSEd Tanous 15785143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15793648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 15803648c8beSEd Tanous 15817e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15827e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1583c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1584c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1585c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1586029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1587c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1588c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1589c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1590cb92c03bSAndrew Geissler 15914978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1592c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 15937e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 15947e860f15SJohn Edward Broadbent // entry 159595820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 159695820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1597b01bf299SEd Tanous uint64_t entryCount = 0; 1598cd225da8SJason M. Bills std::string logEntry; 159995820184SJason M. Bills 16007e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16017e860f15SJohn Edward Broadbent // backwards 1602002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1603002d39b4SEd Tanous it++) 1604c4bf6374SJason M. Bills { 1605cd225da8SJason M. Bills std::ifstream logStream(*it); 160695820184SJason M. Bills if (!logStream.is_open()) 1607c4bf6374SJason M. Bills { 1608c4bf6374SJason M. Bills continue; 1609c4bf6374SJason M. Bills } 1610c4bf6374SJason M. Bills 1611e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1612e85d6b16SJason M. Bills bool firstEntry = true; 161395820184SJason M. Bills while (std::getline(logStream, logEntry)) 161495820184SJason M. Bills { 1615c4bf6374SJason M. Bills std::string idStr; 1616e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1617c4bf6374SJason M. Bills { 1618c4bf6374SJason M. Bills continue; 1619c4bf6374SJason M. Bills } 1620e85d6b16SJason M. Bills firstEntry = false; 1621e85d6b16SJason M. Bills 1622de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 162389492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 162489492a15SPatrick Williams bmcLogEntry); 1625ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1626ac992cdeSJason M. Bills { 1627ac992cdeSJason M. Bills continue; 1628ac992cdeSJason M. Bills } 1629ac992cdeSJason M. Bills if (status != LogParseError::success) 1630c4bf6374SJason M. Bills { 1631c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1632c4bf6374SJason M. Bills return; 1633c4bf6374SJason M. Bills } 1634de703c5dSJason M. Bills 1635de703c5dSJason M. Bills entryCount++; 1636de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1637de703c5dSJason M. Bills // start) and top (number of entries to display) 16383648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1639de703c5dSJason M. Bills { 1640de703c5dSJason M. Bills continue; 1641de703c5dSJason M. Bills } 1642de703c5dSJason M. Bills 1643b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1644c4bf6374SJason M. Bills } 164595820184SJason M. Bills } 1646c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16473648c8beSEd Tanous if (skip + top < entryCount) 1648c4bf6374SJason M. Bills { 1649c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 16504978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 16513648c8beSEd Tanous std::to_string(skip + top); 1652c4bf6374SJason M. Bills } 16537e860f15SJohn Edward Broadbent }); 1654897967deSJason M. Bills } 1655897967deSJason M. Bills 16567e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1657897967deSJason M. Bills { 16587e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 165922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1660ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 16617e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 166245ca1b86SEd Tanous [&app](const crow::Request& req, 16637e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 166422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16653ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 166645ca1b86SEd Tanous { 166745ca1b86SEd Tanous return; 166845ca1b86SEd Tanous } 16697f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 16707f3e84a1SEd Tanous { 16717f3e84a1SEd Tanous // Option currently returns no systems. TBD 16727f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16737f3e84a1SEd Tanous systemName); 16747f3e84a1SEd Tanous return; 16757f3e84a1SEd Tanous } 167622d268cbSEd Tanous 167722d268cbSEd Tanous if (systemName != "system") 167822d268cbSEd Tanous { 167922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 168022d268cbSEd Tanous systemName); 168122d268cbSEd Tanous return; 168222d268cbSEd Tanous } 168322d268cbSEd Tanous 16847e860f15SJohn Edward Broadbent const std::string& targetID = param; 16858d1b46d7Szhanghch05 16867e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 16877e860f15SJohn Edward Broadbent // entry to find the target entry 1688897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1689897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1690897967deSJason M. Bills std::string logEntry; 1691897967deSJason M. Bills 16927e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16937e860f15SJohn Edward Broadbent // backwards 1694002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1695002d39b4SEd Tanous it++) 1696897967deSJason M. Bills { 1697897967deSJason M. Bills std::ifstream logStream(*it); 1698897967deSJason M. Bills if (!logStream.is_open()) 1699897967deSJason M. Bills { 1700897967deSJason M. Bills continue; 1701897967deSJason M. Bills } 1702897967deSJason M. Bills 1703897967deSJason M. Bills // Reset the unique ID on the first entry 1704897967deSJason M. Bills bool firstEntry = true; 1705897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1706897967deSJason M. Bills { 1707897967deSJason M. Bills std::string idStr; 1708897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1709897967deSJason M. Bills { 1710897967deSJason M. Bills continue; 1711897967deSJason M. Bills } 1712897967deSJason M. Bills firstEntry = false; 1713897967deSJason M. Bills 1714897967deSJason M. Bills if (idStr == targetID) 1715897967deSJason M. Bills { 1716de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1717ac992cdeSJason M. Bills LogParseError status = 1718ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1719ac992cdeSJason M. Bills if (status != LogParseError::success) 1720897967deSJason M. Bills { 1721897967deSJason M. Bills messages::internalError(asyncResp->res); 1722897967deSJason M. Bills return; 1723897967deSJason M. Bills } 1724d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1725897967deSJason M. Bills return; 1726897967deSJason M. Bills } 1727897967deSJason M. Bills } 1728897967deSJason M. Bills } 1729897967deSJason M. Bills // Requested ID was not found 17309db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 17317e860f15SJohn Edward Broadbent }); 173208a4e4b5SAnthony Wilson } 173308a4e4b5SAnthony Wilson 17347e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 173508a4e4b5SAnthony Wilson { 173622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1737ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1738002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1739002d39b4SEd Tanous [&app](const crow::Request& req, 174022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174122d268cbSEd Tanous const std::string& systemName) { 17423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 174345ca1b86SEd Tanous { 174445ca1b86SEd Tanous return; 174545ca1b86SEd Tanous } 17467f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 17477f3e84a1SEd Tanous { 17487f3e84a1SEd Tanous // Option currently returns no systems. TBD 17497f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17507f3e84a1SEd Tanous systemName); 17517f3e84a1SEd Tanous return; 17527f3e84a1SEd Tanous } 175322d268cbSEd Tanous if (systemName != "system") 175422d268cbSEd Tanous { 175522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 175622d268cbSEd Tanous systemName); 175722d268cbSEd Tanous return; 175822d268cbSEd Tanous } 175922d268cbSEd Tanous 17607e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 17617e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 176208a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 176308a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 176408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 176508a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 176608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 176708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 176808a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 176908a4e4b5SAnthony Wilson 1770cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1771cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 17725eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 17735eb468daSGeorge Liu dbus::utility::getManagedObjects( 17745eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 17755e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1776914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1777cb92c03bSAndrew Geissler if (ec) 1778cb92c03bSAndrew Geissler { 1779cb92c03bSAndrew Geissler // TODO Handle for specific error code 178062598e31SEd Tanous BMCWEB_LOG_ERROR( 178162598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1782cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1783cb92c03bSAndrew Geissler return; 1784cb92c03bSAndrew Geissler } 17853544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 17869eb808c1SEd Tanous for (const auto& objectPath : resp) 1787cb92c03bSAndrew Geissler { 1788914e2d5dSEd Tanous const uint32_t* id = nullptr; 1789c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1790c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1791914e2d5dSEd Tanous const std::string* severity = nullptr; 1792914e2d5dSEd Tanous const std::string* message = nullptr; 1793914e2d5dSEd Tanous const std::string* filePath = nullptr; 17949c11a172SVijay Lobo const std::string* resolution = nullptr; 179575710de2SXiaochao Ma bool resolved = false; 17969017faf2SAbhishek Patel const std::string* notify = nullptr; 17979017faf2SAbhishek Patel 17989eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1799f86bb901SAdriana Kobylak { 1800f86bb901SAdriana Kobylak if (interfaceMap.first == 1801f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1802f86bb901SAdriana Kobylak { 1803002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1804cb92c03bSAndrew Geissler { 1805cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1806cb92c03bSAndrew Geissler { 1807002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1808cb92c03bSAndrew Geissler } 1809cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1810cb92c03bSAndrew Geissler { 1811002d39b4SEd Tanous timestamp = 1812002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18137e860f15SJohn Edward Broadbent } 1814002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 18157e860f15SJohn Edward Broadbent { 1816002d39b4SEd Tanous updateTimestamp = 1817002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18187e860f15SJohn Edward Broadbent } 18197e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 18207e860f15SJohn Edward Broadbent { 18217e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 18227e860f15SJohn Edward Broadbent &propertyMap.second); 18237e860f15SJohn Edward Broadbent } 18249c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 18259c11a172SVijay Lobo { 18269c11a172SVijay Lobo resolution = std::get_if<std::string>( 18279c11a172SVijay Lobo &propertyMap.second); 18289c11a172SVijay Lobo } 18297e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 18307e860f15SJohn Edward Broadbent { 18317e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 18327e860f15SJohn Edward Broadbent &propertyMap.second); 18337e860f15SJohn Edward Broadbent } 18347e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 18357e860f15SJohn Edward Broadbent { 1836914e2d5dSEd Tanous const bool* resolveptr = 1837002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 18387e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 18397e860f15SJohn Edward Broadbent { 1840002d39b4SEd Tanous messages::internalError(asyncResp->res); 18417e860f15SJohn Edward Broadbent return; 18427e860f15SJohn Edward Broadbent } 18437e860f15SJohn Edward Broadbent resolved = *resolveptr; 18447e860f15SJohn Edward Broadbent } 18459017faf2SAbhishek Patel else if (propertyMap.first == 18469017faf2SAbhishek Patel "ServiceProviderNotify") 18479017faf2SAbhishek Patel { 18489017faf2SAbhishek Patel notify = std::get_if<std::string>( 18499017faf2SAbhishek Patel &propertyMap.second); 18509017faf2SAbhishek Patel if (notify == nullptr) 18519017faf2SAbhishek Patel { 18529017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18539017faf2SAbhishek Patel return; 18549017faf2SAbhishek Patel } 18559017faf2SAbhishek Patel } 18567e860f15SJohn Edward Broadbent } 18577e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 18587e860f15SJohn Edward Broadbent severity == nullptr) 18597e860f15SJohn Edward Broadbent { 18607e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18617e860f15SJohn Edward Broadbent return; 18627e860f15SJohn Edward Broadbent } 18637e860f15SJohn Edward Broadbent } 18647e860f15SJohn Edward Broadbent else if (interfaceMap.first == 18657e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 18667e860f15SJohn Edward Broadbent { 1867002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 18687e860f15SJohn Edward Broadbent { 18697e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 18707e860f15SJohn Edward Broadbent { 18717e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 18727e860f15SJohn Edward Broadbent &propertyMap.second); 18737e860f15SJohn Edward Broadbent } 18747e860f15SJohn Edward Broadbent } 18757e860f15SJohn Edward Broadbent } 18767e860f15SJohn Edward Broadbent } 18777e860f15SJohn Edward Broadbent // Object path without the 18787e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 18797e860f15SJohn Edward Broadbent // and continue. 18807e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1881c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1882c419c759SEd Tanous updateTimestamp == nullptr) 18837e860f15SJohn Edward Broadbent { 18847e860f15SJohn Edward Broadbent continue; 18857e860f15SJohn Edward Broadbent } 18863544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 18879c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1888ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1889ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1890ef4c65b7SEd Tanous std::to_string(*id)); 18917e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 18927e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 18937e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 18947e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 18959c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18969c11a172SVijay Lobo { 18979c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 18989c11a172SVijay Lobo } 18999017faf2SAbhishek Patel std::optional<bool> notifyAction = 19009017faf2SAbhishek Patel getProviderNotifyAction(*notify); 19019017faf2SAbhishek Patel if (notifyAction) 19029017faf2SAbhishek Patel { 19039017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 19049017faf2SAbhishek Patel } 19057e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 19067e860f15SJohn Edward Broadbent thisEntry["Severity"] = 19077e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 19087e860f15SJohn Edward Broadbent thisEntry["Created"] = 19092b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 19107e860f15SJohn Edward Broadbent thisEntry["Modified"] = 19112b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 19127e860f15SJohn Edward Broadbent if (filePath != nullptr) 19137e860f15SJohn Edward Broadbent { 19147e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 19150fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 19167e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 19177e860f15SJohn Edward Broadbent } 19187e860f15SJohn Edward Broadbent } 19193544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 19203544d2a7SEd Tanous const nlohmann::json& right) { 19217e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 19227e860f15SJohn Edward Broadbent }); 19237e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 19247e860f15SJohn Edward Broadbent entriesArray.size(); 19253544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 19265eb468daSGeorge Liu }); 19277e860f15SJohn Edward Broadbent }); 19287e860f15SJohn Edward Broadbent } 19297e860f15SJohn Edward Broadbent 19307e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 19317e860f15SJohn Edward Broadbent { 19327e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 193322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1934ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1935002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1936002d39b4SEd Tanous [&app](const crow::Request& req, 19377e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 193822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19407e860f15SJohn Edward Broadbent { 194145ca1b86SEd Tanous return; 194245ca1b86SEd Tanous } 19437f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19447f3e84a1SEd Tanous { 19457f3e84a1SEd Tanous // Option currently returns no systems. TBD 19467f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19477f3e84a1SEd Tanous systemName); 19487f3e84a1SEd Tanous return; 19497f3e84a1SEd Tanous } 195022d268cbSEd Tanous if (systemName != "system") 195122d268cbSEd Tanous { 195222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 195322d268cbSEd Tanous systemName); 195422d268cbSEd Tanous return; 195522d268cbSEd Tanous } 195622d268cbSEd Tanous 19577e860f15SJohn Edward Broadbent std::string entryID = param; 19587e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 19597e860f15SJohn Edward Broadbent 19607e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 19617e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1962d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1963d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1964d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 19655e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1966b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 19677e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 19687e860f15SJohn Edward Broadbent { 1969d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1970d1bde9e5SKrzysztof Grobelny entryID); 19717e860f15SJohn Edward Broadbent return; 19727e860f15SJohn Edward Broadbent } 19737e860f15SJohn Edward Broadbent if (ec) 19747e860f15SJohn Edward Broadbent { 197562598e31SEd Tanous BMCWEB_LOG_ERROR( 197662598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 19777e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 19787e860f15SJohn Edward Broadbent return; 19797e860f15SJohn Edward Broadbent } 1980914e2d5dSEd Tanous const uint32_t* id = nullptr; 1981c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1982c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1983914e2d5dSEd Tanous const std::string* severity = nullptr; 1984914e2d5dSEd Tanous const std::string* message = nullptr; 1985914e2d5dSEd Tanous const std::string* filePath = nullptr; 19869c11a172SVijay Lobo const std::string* resolution = nullptr; 19877e860f15SJohn Edward Broadbent bool resolved = false; 19889017faf2SAbhishek Patel const std::string* notify = nullptr; 19897e860f15SJohn Edward Broadbent 1990d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1991d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1992d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 19939c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 19949017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 19959017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1996d1bde9e5SKrzysztof Grobelny 1997d1bde9e5SKrzysztof Grobelny if (!success) 199875710de2SXiaochao Ma { 199975710de2SXiaochao Ma messages::internalError(asyncResp->res); 200075710de2SXiaochao Ma return; 200175710de2SXiaochao Ma } 2002d1bde9e5SKrzysztof Grobelny 2003002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 20049017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 20059017faf2SAbhishek Patel notify == nullptr) 2006f86bb901SAdriana Kobylak { 2007ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 2008271584abSEd Tanous return; 2009271584abSEd Tanous } 20109017faf2SAbhishek Patel 2011f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 20129c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 2013ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2014ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 2015ef4c65b7SEd Tanous std::to_string(*id)); 201645ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 2017f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 2018f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 2019f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 20209017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 20219017faf2SAbhishek Patel if (notifyAction) 20229017faf2SAbhishek Patel { 20239017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 20249017faf2SAbhishek Patel *notifyAction; 20259017faf2SAbhishek Patel } 20269c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 20279c11a172SVijay Lobo { 20289c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 20299c11a172SVijay Lobo } 2030f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 2031f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 2032f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 2033f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 20342b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 2035f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 20362b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 2037f86bb901SAdriana Kobylak if (filePath != nullptr) 2038f86bb901SAdriana Kobylak { 2039f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 2040e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 2041e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 2042f86bb901SAdriana Kobylak } 2043d1bde9e5SKrzysztof Grobelny }); 20447e860f15SJohn Edward Broadbent }); 2045336e96c6SChicago Duan 20467e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 204722d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2048ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 20497e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 205045ca1b86SEd Tanous [&app](const crow::Request& req, 20517e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 205222d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 20533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 205445ca1b86SEd Tanous { 205545ca1b86SEd Tanous return; 205645ca1b86SEd Tanous } 20577f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20587f3e84a1SEd Tanous { 20597f3e84a1SEd Tanous // Option currently returns no systems. TBD 20607f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20617f3e84a1SEd Tanous systemName); 20627f3e84a1SEd Tanous return; 20637f3e84a1SEd Tanous } 206422d268cbSEd Tanous if (systemName != "system") 206522d268cbSEd Tanous { 206622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 206722d268cbSEd Tanous systemName); 206822d268cbSEd Tanous return; 206922d268cbSEd Tanous } 207075710de2SXiaochao Ma std::optional<bool> resolved; 207175710de2SXiaochao Ma 207215ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 20737e860f15SJohn Edward Broadbent resolved)) 207475710de2SXiaochao Ma { 207575710de2SXiaochao Ma return; 207675710de2SXiaochao Ma } 207762598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 207875710de2SXiaochao Ma 20799ae226faSGeorge Liu sdbusplus::asio::setProperty( 20809ae226faSGeorge Liu *crow::connections::systemBus, "xyz.openbmc_project.Logging", 20819ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 20829ae226faSGeorge Liu "xyz.openbmc_project.Logging.Entry", "Resolved", *resolved, 20835e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 208475710de2SXiaochao Ma if (ec) 208575710de2SXiaochao Ma { 208662598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 208775710de2SXiaochao Ma messages::internalError(asyncResp->res); 208875710de2SXiaochao Ma return; 208975710de2SXiaochao Ma } 20909ae226faSGeorge Liu }); 20917e860f15SJohn Edward Broadbent }); 209275710de2SXiaochao Ma 20937e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 209422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2095ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2096ed398213SEd Tanous 2097002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2098002d39b4SEd Tanous [&app](const crow::Request& req, 2099002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 210022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21013ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2102336e96c6SChicago Duan { 210345ca1b86SEd Tanous return; 210445ca1b86SEd Tanous } 21057f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 21067f3e84a1SEd Tanous { 21077f3e84a1SEd Tanous // Option currently returns no systems. TBD 21087f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21097f3e84a1SEd Tanous systemName); 21107f3e84a1SEd Tanous return; 21117f3e84a1SEd Tanous } 211222d268cbSEd Tanous if (systemName != "system") 211322d268cbSEd Tanous { 211422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 211522d268cbSEd Tanous systemName); 211622d268cbSEd Tanous return; 211722d268cbSEd Tanous } 211862598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 2119336e96c6SChicago Duan 21207e860f15SJohn Edward Broadbent std::string entryID = param; 2121336e96c6SChicago Duan 2122336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 2123336e96c6SChicago Duan 2124336e96c6SChicago Duan // Process response from Logging service. 21255a39f77aSPatrick Williams auto respHandler = [asyncResp, 21265a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 212762598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 2128336e96c6SChicago Duan if (ec) 2129336e96c6SChicago Duan { 21303de8d8baSGeorge Liu if (ec.value() == EBADR) 21313de8d8baSGeorge Liu { 213245ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 213345ca1b86SEd Tanous entryID); 21343de8d8baSGeorge Liu return; 21353de8d8baSGeorge Liu } 2136336e96c6SChicago Duan // TODO Handle for specific error code 213762598e31SEd Tanous BMCWEB_LOG_ERROR( 213862598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 213962598e31SEd Tanous ec); 2140336e96c6SChicago Duan asyncResp->res.result( 2141336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 2142336e96c6SChicago Duan return; 2143336e96c6SChicago Duan } 2144336e96c6SChicago Duan 2145336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 2146336e96c6SChicago Duan }; 2147336e96c6SChicago Duan 2148336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2149336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2150336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2151336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2152336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 21537e860f15SJohn Edward Broadbent }); 2154400fd1fbSAdriana Kobylak } 2155400fd1fbSAdriana Kobylak 2156b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2157b7028ebfSSpencer Ku 2158b7028ebfSSpencer Ku inline bool 2159b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2160b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2161b7028ebfSSpencer Ku { 2162b7028ebfSSpencer Ku std::error_code ec; 2163b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2164b7028ebfSSpencer Ku if (ec) 2165b7028ebfSSpencer Ku { 2166bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2167b7028ebfSSpencer Ku return false; 2168b7028ebfSSpencer Ku } 2169b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2170b7028ebfSSpencer Ku { 2171b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2172b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2173b7028ebfSSpencer Ku // path 217411ba3979SEd Tanous if (filename.starts_with("log")) 2175b7028ebfSSpencer Ku { 2176b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2177b7028ebfSSpencer Ku } 2178b7028ebfSSpencer Ku } 2179b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2180b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2181b7028ebfSSpencer Ku // descending order. 2182b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2183b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2184b7028ebfSSpencer Ku 2185b7028ebfSSpencer Ku return true; 2186b7028ebfSSpencer Ku } 2187b7028ebfSSpencer Ku 218802cad96eSEd Tanous inline bool getHostLoggerEntries( 218902cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 219002cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2191b7028ebfSSpencer Ku { 2192b7028ebfSSpencer Ku GzFileReader logFile; 2193b7028ebfSSpencer Ku 2194b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2195b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2196b7028ebfSSpencer Ku { 2197b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2198b7028ebfSSpencer Ku { 219962598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2200b7028ebfSSpencer Ku return false; 2201b7028ebfSSpencer Ku } 2202b7028ebfSSpencer Ku } 2203b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2204b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2205b7028ebfSSpencer Ku if (!lastMessage.empty()) 2206b7028ebfSSpencer Ku { 2207b7028ebfSSpencer Ku logCount++; 2208b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2209b7028ebfSSpencer Ku { 2210b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2211b7028ebfSSpencer Ku } 2212b7028ebfSSpencer Ku } 2213b7028ebfSSpencer Ku return true; 2214b7028ebfSSpencer Ku } 2215b7028ebfSSpencer Ku 2216b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2217b7028ebfSSpencer Ku const std::string& msg, 22186d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2219b7028ebfSSpencer Ku { 2220b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 22219c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2222ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2223ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2224ef4c65b7SEd Tanous logEntryID); 22256d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 22266d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 22276d6574c9SJason M. Bills logEntryJson["Message"] = msg; 22286d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 22296d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 22306d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2231b7028ebfSSpencer Ku } 2232b7028ebfSSpencer Ku 2233b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2234b7028ebfSSpencer Ku { 223522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2236b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 22371476687dSEd Tanous .methods(boost::beast::http::verb::get)( 22381476687dSEd Tanous [&app](const crow::Request& req, 223922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 224022d268cbSEd Tanous const std::string& systemName) { 22413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 224245ca1b86SEd Tanous { 224345ca1b86SEd Tanous return; 224445ca1b86SEd Tanous } 22457f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22467f3e84a1SEd Tanous { 22477f3e84a1SEd Tanous // Option currently returns no systems. TBD 22487f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22497f3e84a1SEd Tanous systemName); 22507f3e84a1SEd Tanous return; 22517f3e84a1SEd Tanous } 225222d268cbSEd Tanous if (systemName != "system") 225322d268cbSEd Tanous { 225422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 225522d268cbSEd Tanous systemName); 225622d268cbSEd Tanous return; 225722d268cbSEd Tanous } 2258b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2259b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2260b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2261b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2262b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2263b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2264b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 22651476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 22661476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2267b7028ebfSSpencer Ku }); 2268b7028ebfSSpencer Ku } 2269b7028ebfSSpencer Ku 2270b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2271b7028ebfSSpencer Ku { 2272b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 227322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2274b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2275002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2276002d39b4SEd Tanous [&app](const crow::Request& req, 227722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 227822d268cbSEd Tanous const std::string& systemName) { 2279c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2280c937d2bfSEd Tanous .canDelegateTop = true, 2281c937d2bfSEd Tanous .canDelegateSkip = true, 2282c937d2bfSEd Tanous }; 2283c937d2bfSEd Tanous query_param::Query delegatedQuery; 2284c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22853ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2286b7028ebfSSpencer Ku { 2287b7028ebfSSpencer Ku return; 2288b7028ebfSSpencer Ku } 22897f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22907f3e84a1SEd Tanous { 22917f3e84a1SEd Tanous // Option currently returns no systems. TBD 22927f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22937f3e84a1SEd Tanous systemName); 22947f3e84a1SEd Tanous return; 22957f3e84a1SEd Tanous } 229622d268cbSEd Tanous if (systemName != "system") 229722d268cbSEd Tanous { 229822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 229922d268cbSEd Tanous systemName); 230022d268cbSEd Tanous return; 230122d268cbSEd Tanous } 2302b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2303b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2304b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2305b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2306b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2307b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2308b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 23090fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2310b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2311b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2312b7028ebfSSpencer Ku 2313b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2314b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2315b7028ebfSSpencer Ku { 2316bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2317b7028ebfSSpencer Ku return; 2318b7028ebfSSpencer Ku } 23193648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 23203648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 23215143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2322b7028ebfSSpencer Ku size_t logCount = 0; 2323b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2324b7028ebfSSpencer Ku // control by skip and top. 2325b7028ebfSSpencer Ku std::vector<std::string> logEntries; 23263648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 23273648c8beSEd Tanous logCount)) 2328b7028ebfSSpencer Ku { 2329b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2330b7028ebfSSpencer Ku return; 2331b7028ebfSSpencer Ku } 2332b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2333b7028ebfSSpencer Ku // log count 233426f6976fSEd Tanous if (logEntries.empty()) 2335b7028ebfSSpencer Ku { 2336b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2337b7028ebfSSpencer Ku return; 2338b7028ebfSSpencer Ku } 233926f6976fSEd Tanous if (!logEntries.empty()) 2340b7028ebfSSpencer Ku { 2341b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2342b7028ebfSSpencer Ku { 23436d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23443648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 23453648c8beSEd Tanous hostLogEntry); 2346b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2347b7028ebfSSpencer Ku } 2348b7028ebfSSpencer Ku 2349b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 23503648c8beSEd Tanous if (skip + top < logCount) 2351b7028ebfSSpencer Ku { 2352b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 23530fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 23543648c8beSEd Tanous std::to_string(skip + top); 2355b7028ebfSSpencer Ku } 2356b7028ebfSSpencer Ku } 2357b7028ebfSSpencer Ku }); 2358b7028ebfSSpencer Ku } 2359b7028ebfSSpencer Ku 2360b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2361b7028ebfSSpencer Ku { 2362b7028ebfSSpencer Ku BMCWEB_ROUTE( 236322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2364b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2365b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 236645ca1b86SEd Tanous [&app](const crow::Request& req, 2367b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 236822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 23693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 237045ca1b86SEd Tanous { 237145ca1b86SEd Tanous return; 237245ca1b86SEd Tanous } 23737f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 23747f3e84a1SEd Tanous { 23757f3e84a1SEd Tanous // Option currently returns no systems. TBD 23767f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 23777f3e84a1SEd Tanous systemName); 23787f3e84a1SEd Tanous return; 23797f3e84a1SEd Tanous } 238022d268cbSEd Tanous if (systemName != "system") 238122d268cbSEd Tanous { 238222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 238322d268cbSEd Tanous systemName); 238422d268cbSEd Tanous return; 238522d268cbSEd Tanous } 2386b7028ebfSSpencer Ku const std::string& targetID = param; 2387b7028ebfSSpencer Ku 2388b7028ebfSSpencer Ku uint64_t idInt = 0; 2389ca45aa3cSEd Tanous 239084396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 239184396af9SPatrick Williams idInt); 23929db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 23939db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2394b7028ebfSSpencer Ku { 23959db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2396b7028ebfSSpencer Ku return; 2397b7028ebfSSpencer Ku } 2398b7028ebfSSpencer Ku 2399b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2400b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2401b7028ebfSSpencer Ku { 2402bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2403b7028ebfSSpencer Ku return; 2404b7028ebfSSpencer Ku } 2405b7028ebfSSpencer Ku 2406b7028ebfSSpencer Ku size_t logCount = 0; 24073648c8beSEd Tanous size_t top = 1; 2408b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2409b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2410b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2411b7028ebfSSpencer Ku // get that entry 2412002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2413002d39b4SEd Tanous logCount)) 2414b7028ebfSSpencer Ku { 2415b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2416b7028ebfSSpencer Ku return; 2417b7028ebfSSpencer Ku } 2418b7028ebfSSpencer Ku 2419b7028ebfSSpencer Ku if (!logEntries.empty()) 2420b7028ebfSSpencer Ku { 24216d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 24226d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 24236d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2424b7028ebfSSpencer Ku return; 2425b7028ebfSSpencer Ku } 2426b7028ebfSSpencer Ku 2427b7028ebfSSpencer Ku // Requested ID was not found 24289db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2429b7028ebfSSpencer Ku }); 2430b7028ebfSSpencer Ku } 2431b7028ebfSSpencer Ku 2432dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2433fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2434fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 24351da66f75SEd Tanous { 24363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 243745ca1b86SEd Tanous { 243845ca1b86SEd Tanous return; 243945ca1b86SEd Tanous } 24407e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24417e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2442e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 24431da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2444e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2445e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2446002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2447e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 24481da66f75SEd Tanous "Collection of LogServices for this Manager"; 2449002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2450c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2451fdd26906SClaire Weinan 2452c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2453613dabeaSEd Tanous nlohmann::json::object_t journal; 2454613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2455b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2456c4bf6374SJason M. Bills #endif 2457fdd26906SClaire Weinan 2458fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2459fdd26906SClaire Weinan 2460fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 246115912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24627a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 24637a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 24647a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2465fdd26906SClaire Weinan [asyncResp]( 24667a1dbc48SGeorge Liu const boost::system::error_code& ec, 2467fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2468fdd26906SClaire Weinan if (ec) 2469fdd26906SClaire Weinan { 247062598e31SEd Tanous BMCWEB_LOG_ERROR( 247162598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 247262598e31SEd Tanous ec); 2473fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2474fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2475fdd26906SClaire Weinan return; 2476fdd26906SClaire Weinan } 2477fdd26906SClaire Weinan 2478fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2479fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2480fdd26906SClaire Weinan 2481fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2482fdd26906SClaire Weinan { 2483fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2484fdd26906SClaire Weinan { 2485613dabeaSEd Tanous nlohmann::json::object_t member; 2486613dabeaSEd Tanous member["@odata.id"] = 2487613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2488b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2489fdd26906SClaire Weinan } 2490fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2491fdd26906SClaire Weinan { 2492613dabeaSEd Tanous nlohmann::json::object_t member; 2493613dabeaSEd Tanous member["@odata.id"] = 2494613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2495b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2496fdd26906SClaire Weinan } 2497fdd26906SClaire Weinan } 2498fdd26906SClaire Weinan 2499e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2500fdd26906SClaire Weinan logServiceArrayLocal.size(); 25017a1dbc48SGeorge Liu }); 2502fdd26906SClaire Weinan #endif 2503fdd26906SClaire Weinan } 2504fdd26906SClaire Weinan 2505fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2506fdd26906SClaire Weinan { 2507fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2508fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2509fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2510dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2511e1f26343SJason M. Bills } 2512e1f26343SJason M. Bills 25137e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2514e1f26343SJason M. Bills { 25157e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2516ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 25177e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 251845ca1b86SEd Tanous [&app](const crow::Request& req, 251945ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 25203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25217e860f15SJohn Edward Broadbent { 252245ca1b86SEd Tanous return; 252345ca1b86SEd Tanous } 2524e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2525b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 25260f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 25270f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2528002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2529002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2530ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2531e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 25327c8c4058STejas Patil 25337c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 25342b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2535002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 25367c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 25377c8c4058STejas Patil redfishDateTimeOffset.second; 25387c8c4058STejas Patil 25391476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 25401476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 25417e860f15SJohn Edward Broadbent }); 2542e1f26343SJason M. Bills } 2543e1f26343SJason M. Bills 25443a48b3a2SJason M. Bills static int 25453a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2546e1f26343SJason M. Bills sd_journal* journal, 25473a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2548e1f26343SJason M. Bills { 2549e1f26343SJason M. Bills // Get the Log Entry contents 2550e1f26343SJason M. Bills int ret = 0; 2551e1f26343SJason M. Bills 2552a8fe54f0SJason M. Bills std::string message; 2553a8fe54f0SJason M. Bills std::string_view syslogID; 2554a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2555a8fe54f0SJason M. Bills if (ret < 0) 2556a8fe54f0SJason M. Bills { 2557bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 255862598e31SEd Tanous strerror(-ret)); 2559a8fe54f0SJason M. Bills } 2560a8fe54f0SJason M. Bills if (!syslogID.empty()) 2561a8fe54f0SJason M. Bills { 2562a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2563a8fe54f0SJason M. Bills } 2564a8fe54f0SJason M. Bills 256539e77504SEd Tanous std::string_view msg; 256616428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2567e1f26343SJason M. Bills if (ret < 0) 2568e1f26343SJason M. Bills { 256962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2570e1f26343SJason M. Bills return 1; 2571e1f26343SJason M. Bills } 2572a8fe54f0SJason M. Bills message += std::string(msg); 2573e1f26343SJason M. Bills 2574e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2575271584abSEd Tanous long int severity = 8; // Default to an invalid priority 257616428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2577e1f26343SJason M. Bills if (ret < 0) 2578e1f26343SJason M. Bills { 2579bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2580e1f26343SJason M. Bills } 2581e1f26343SJason M. Bills 2582e1f26343SJason M. Bills // Get the Created time from the timestamp 258316428a1aSJason M. Bills std::string entryTimeStr; 258416428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2585e1f26343SJason M. Bills { 258616428a1aSJason M. Bills return 1; 2587e1f26343SJason M. Bills } 2588e1f26343SJason M. Bills 2589e1f26343SJason M. Bills // Fill in the log entry with the gathered data 25909c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2591ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2592ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2593eddfc437SWilly Tu bmcJournalLogEntryID); 259484afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 259584afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 259684afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 259784afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 259884afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2599738c1e61SPatrick Williams : severity <= 4 ? "Warning" 260084afc48bSJason M. Bills : "OK"; 260184afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 260284afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2603e1f26343SJason M. Bills return 0; 2604e1f26343SJason M. Bills } 2605e1f26343SJason M. Bills 26067e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2607e1f26343SJason M. Bills { 26087e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2609ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2610002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2611002d39b4SEd Tanous [&app](const crow::Request& req, 2612002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2613c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2614c937d2bfSEd Tanous .canDelegateTop = true, 2615c937d2bfSEd Tanous .canDelegateSkip = true, 2616c937d2bfSEd Tanous }; 2617c937d2bfSEd Tanous query_param::Query delegatedQuery; 2618c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 26193ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2620193ad2faSJason M. Bills { 2621193ad2faSJason M. Bills return; 2622193ad2faSJason M. Bills } 26233648c8beSEd Tanous 26243648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 26255143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 26263648c8beSEd Tanous 26277e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 26287e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2629e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2630e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 26310f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 26320f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2633e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2634e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2635e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 26360fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2637e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2638e1f26343SJason M. Bills 26397e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 26407e860f15SJohn Edward Broadbent // unique ID for each entry 2641e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2642e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2643e1f26343SJason M. Bills if (ret < 0) 2644e1f26343SJason M. Bills { 264562598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2646f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2647e1f26343SJason M. Bills return; 2648e1f26343SJason M. Bills } 26490fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 26500fda0f12SGeorge Liu journalTmp, sd_journal_close); 2651e1f26343SJason M. Bills journalTmp = nullptr; 2652b01bf299SEd Tanous uint64_t entryCount = 0; 2653e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2654e85d6b16SJason M. Bills bool firstEntry = true; 2655e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2656e1f26343SJason M. Bills { 2657193ad2faSJason M. Bills entryCount++; 26587e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 26597e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 26603648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2661193ad2faSJason M. Bills { 2662193ad2faSJason M. Bills continue; 2663193ad2faSJason M. Bills } 2664193ad2faSJason M. Bills 266516428a1aSJason M. Bills std::string idStr; 2666e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2667e1f26343SJason M. Bills { 2668e1f26343SJason M. Bills continue; 2669e1f26343SJason M. Bills } 2670e85d6b16SJason M. Bills firstEntry = false; 2671e85d6b16SJason M. Bills 26723a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2673c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2674c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2675e1f26343SJason M. Bills { 2676f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2677e1f26343SJason M. Bills return; 2678e1f26343SJason M. Bills } 2679b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2680e1f26343SJason M. Bills } 2681193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 26823648c8beSEd Tanous if (skip + top < entryCount) 2683193ad2faSJason M. Bills { 2684193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 26850fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 26863648c8beSEd Tanous std::to_string(skip + top); 2687193ad2faSJason M. Bills } 26887e860f15SJohn Edward Broadbent }); 2689e1f26343SJason M. Bills } 2690e1f26343SJason M. Bills 26917e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2692e1f26343SJason M. Bills { 26937e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26947e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2695ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 26967e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 269745ca1b86SEd Tanous [&app](const crow::Request& req, 26987e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26997e860f15SJohn Edward Broadbent const std::string& entryID) { 27003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270145ca1b86SEd Tanous { 270245ca1b86SEd Tanous return; 270345ca1b86SEd Tanous } 2704e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 270575e8e218SMyung Bae sd_id128_t bootID{}; 2706e1f26343SJason M. Bills uint64_t ts = 0; 2707271584abSEd Tanous uint64_t index = 0; 270875e8e218SMyung Bae if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index)) 2709e1f26343SJason M. Bills { 271016428a1aSJason M. Bills return; 2711e1f26343SJason M. Bills } 2712e1f26343SJason M. Bills 2713e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2714e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2715e1f26343SJason M. Bills if (ret < 0) 2716e1f26343SJason M. Bills { 271762598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2718f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2719e1f26343SJason M. Bills return; 2720e1f26343SJason M. Bills } 2721002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2722002d39b4SEd Tanous journalTmp, sd_journal_close); 2723e1f26343SJason M. Bills journalTmp = nullptr; 27247e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 27257e860f15SJohn Edward Broadbent // index tracking the unique ID 2726af07e3f5SJason M. Bills std::string idStr; 2727af07e3f5SJason M. Bills bool firstEntry = true; 272875e8e218SMyung Bae ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts); 27292056b6d1SManojkiran Eda if (ret < 0) 27302056b6d1SManojkiran Eda { 273162598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 273262598e31SEd Tanous strerror(-ret)); 27332056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 27342056b6d1SManojkiran Eda return; 27352056b6d1SManojkiran Eda } 2736271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2737e1f26343SJason M. Bills { 2738e1f26343SJason M. Bills sd_journal_next(journal.get()); 2739af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2740af07e3f5SJason M. Bills { 2741af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2742af07e3f5SJason M. Bills return; 2743af07e3f5SJason M. Bills } 2744af07e3f5SJason M. Bills firstEntry = false; 2745af07e3f5SJason M. Bills } 2746c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2747af07e3f5SJason M. Bills if (idStr != entryID) 2748c4bf6374SJason M. Bills { 27499db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2750c4bf6374SJason M. Bills return; 2751c4bf6374SJason M. Bills } 2752c4bf6374SJason M. Bills 27533a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2754c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 27553a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2756e1f26343SJason M. Bills { 2757f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2758e1f26343SJason M. Bills return; 2759e1f26343SJason M. Bills } 2760d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 27617e860f15SJohn Edward Broadbent }); 2762c9bb6861Sraviteja-b } 2763c9bb6861Sraviteja-b 2764fdd26906SClaire Weinan inline void 2765fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2766fdd26906SClaire Weinan const std::string& dumpType) 2767c9bb6861Sraviteja-b { 2768fdd26906SClaire Weinan std::string dumpPath; 2769fdd26906SClaire Weinan std::string overWritePolicy; 2770fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2771fdd26906SClaire Weinan 2772fdd26906SClaire Weinan if (dumpType == "BMC") 277345ca1b86SEd Tanous { 2774fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2775fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2776fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2777fdd26906SClaire Weinan } 2778fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2779fdd26906SClaire Weinan { 2780fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2781fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2782fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2783fdd26906SClaire Weinan } 2784fdd26906SClaire Weinan else if (dumpType == "System") 2785fdd26906SClaire Weinan { 2786fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2787fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2788fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2789fdd26906SClaire Weinan } 2790fdd26906SClaire Weinan else 2791fdd26906SClaire Weinan { 279262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 279362598e31SEd Tanous dumpType); 2794fdd26906SClaire Weinan messages::internalError(asyncResp->res); 279545ca1b86SEd Tanous return; 279645ca1b86SEd Tanous } 2797fdd26906SClaire Weinan 2798fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2799fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2800c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2801fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2802fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2803fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 28047c8c4058STejas Patil 28057c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 28062b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 28070fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 28087c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 28097c8c4058STejas Patil redfishDateTimeOffset.second; 28107c8c4058STejas Patil 2811fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2812fdd26906SClaire Weinan 2813fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2814fdd26906SClaire Weinan { 2815002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 28161476687dSEd Tanous ["target"] = 2817fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2818fdd26906SClaire Weinan } 28190d946211SClaire Weinan 28200d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 28210d946211SClaire Weinan dbus::utility::getSubTreePaths( 28220d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 28230d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 28240d946211SClaire Weinan const boost::system::error_code& ec, 28250d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 28260d946211SClaire Weinan if (ec) 28270d946211SClaire Weinan { 282862598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 28290d946211SClaire Weinan // Assume that getting an error simply means there are no dump 28300d946211SClaire Weinan // LogServices. Return without adding any error response. 28310d946211SClaire Weinan return; 28320d946211SClaire Weinan } 2833*18f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 28340d946211SClaire Weinan for (const std::string& path : subTreePaths) 28350d946211SClaire Weinan { 28360d946211SClaire Weinan if (path == dbusDumpPath) 28370d946211SClaire Weinan { 28380d946211SClaire Weinan asyncResp->res 28390d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 28400d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 28410d946211SClaire Weinan break; 28420d946211SClaire Weinan } 28430d946211SClaire Weinan } 28440d946211SClaire Weinan }); 2845c9bb6861Sraviteja-b } 2846c9bb6861Sraviteja-b 2847fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2848fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2849fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 28507e860f15SJohn Edward Broadbent { 28513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 285245ca1b86SEd Tanous { 285345ca1b86SEd Tanous return; 285445ca1b86SEd Tanous } 2855fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2856fdd26906SClaire Weinan } 2857c9bb6861Sraviteja-b 285822d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 285922d268cbSEd Tanous crow::App& app, const crow::Request& req, 286022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286122d268cbSEd Tanous const std::string& chassisId) 286222d268cbSEd Tanous { 286322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 286422d268cbSEd Tanous { 286522d268cbSEd Tanous return; 286622d268cbSEd Tanous } 286722d268cbSEd Tanous if (chassisId != "system") 286822d268cbSEd Tanous { 286922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 287022d268cbSEd Tanous return; 287122d268cbSEd Tanous } 287222d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 287322d268cbSEd Tanous } 287422d268cbSEd Tanous 2875fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2876fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2877fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2878fdd26906SClaire Weinan { 2879fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2880fdd26906SClaire Weinan { 2881fdd26906SClaire Weinan return; 2882fdd26906SClaire Weinan } 2883fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2884fdd26906SClaire Weinan } 2885fdd26906SClaire Weinan 288622d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 288722d268cbSEd Tanous crow::App& app, const crow::Request& req, 288822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 288922d268cbSEd Tanous const std::string& chassisId) 289022d268cbSEd Tanous { 289122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 289222d268cbSEd Tanous { 289322d268cbSEd Tanous return; 289422d268cbSEd Tanous } 289522d268cbSEd Tanous if (chassisId != "system") 289622d268cbSEd Tanous { 289722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 289822d268cbSEd Tanous return; 289922d268cbSEd Tanous } 290022d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 290122d268cbSEd Tanous } 290222d268cbSEd Tanous 2903fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2904fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2905fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2906fdd26906SClaire Weinan const std::string& dumpId) 2907fdd26906SClaire Weinan { 2908fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2909fdd26906SClaire Weinan { 2910fdd26906SClaire Weinan return; 2911fdd26906SClaire Weinan } 2912fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2913fdd26906SClaire Weinan } 2914168d1b1aSCarson Labrado 291522d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 291622d268cbSEd Tanous crow::App& app, const crow::Request& req, 291722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 291822d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 291922d268cbSEd Tanous { 292022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 292122d268cbSEd Tanous { 292222d268cbSEd Tanous return; 292322d268cbSEd Tanous } 292422d268cbSEd Tanous if (chassisId != "system") 292522d268cbSEd Tanous { 292622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 292722d268cbSEd Tanous return; 292822d268cbSEd Tanous } 292922d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 293022d268cbSEd Tanous } 2931fdd26906SClaire Weinan 2932fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2933fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2934fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2935fdd26906SClaire Weinan const std::string& dumpId) 2936fdd26906SClaire Weinan { 2937fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2938fdd26906SClaire Weinan { 2939fdd26906SClaire Weinan return; 2940fdd26906SClaire Weinan } 2941fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2942fdd26906SClaire Weinan } 2943fdd26906SClaire Weinan 294422d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 294522d268cbSEd Tanous crow::App& app, const crow::Request& req, 294622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 294722d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 294822d268cbSEd Tanous { 294922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 295022d268cbSEd Tanous { 295122d268cbSEd Tanous return; 295222d268cbSEd Tanous } 295322d268cbSEd Tanous if (chassisId != "system") 295422d268cbSEd Tanous { 295522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 295622d268cbSEd Tanous return; 295722d268cbSEd Tanous } 295822d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 295922d268cbSEd Tanous } 296022d268cbSEd Tanous 2961168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2962168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2963168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2964168d1b1aSCarson Labrado const std::string& dumpId) 2965168d1b1aSCarson Labrado { 2966168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2967168d1b1aSCarson Labrado { 2968168d1b1aSCarson Labrado return; 2969168d1b1aSCarson Labrado } 2970168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2971168d1b1aSCarson Labrado } 2972168d1b1aSCarson Labrado 2973168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2974168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2975168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2976168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2977168d1b1aSCarson Labrado { 2978168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2979168d1b1aSCarson Labrado { 2980168d1b1aSCarson Labrado return; 2981168d1b1aSCarson Labrado } 2982168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2983168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2984168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2985168d1b1aSCarson Labrado { 2986168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2987168d1b1aSCarson Labrado return; 2988168d1b1aSCarson Labrado } 2989168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2990168d1b1aSCarson Labrado } 2991168d1b1aSCarson Labrado 2992fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2993fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2994fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2995fdd26906SClaire Weinan { 2996fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2997fdd26906SClaire Weinan { 2998fdd26906SClaire Weinan return; 2999fdd26906SClaire Weinan } 3000fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 3001fdd26906SClaire Weinan } 3002fdd26906SClaire Weinan 300322d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 300422d268cbSEd Tanous crow::App& app, const crow::Request& req, 300522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30067f3e84a1SEd Tanous const std::string& systemName) 300722d268cbSEd Tanous { 300822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 300922d268cbSEd Tanous { 301022d268cbSEd Tanous return; 301122d268cbSEd Tanous } 30127f3e84a1SEd Tanous 30137f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 301422d268cbSEd Tanous { 30157f3e84a1SEd Tanous // Option currently returns no systems. TBD 30167f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30177f3e84a1SEd Tanous systemName); 30187f3e84a1SEd Tanous return; 30197f3e84a1SEd Tanous } 30207f3e84a1SEd Tanous if (systemName != "system") 30217f3e84a1SEd Tanous { 30227f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30237f3e84a1SEd Tanous systemName); 302422d268cbSEd Tanous return; 302522d268cbSEd Tanous } 302622d268cbSEd Tanous createDump(asyncResp, req, "System"); 302722d268cbSEd Tanous } 302822d268cbSEd Tanous 3029fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 3030fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3031fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3032fdd26906SClaire Weinan { 3033fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3034fdd26906SClaire Weinan { 3035fdd26906SClaire Weinan return; 3036fdd26906SClaire Weinan } 3037fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 3038fdd26906SClaire Weinan } 3039fdd26906SClaire Weinan 304022d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 304122d268cbSEd Tanous crow::App& app, const crow::Request& req, 304222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30437f3e84a1SEd Tanous const std::string& systemName) 304422d268cbSEd Tanous { 304522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 304622d268cbSEd Tanous { 304722d268cbSEd Tanous return; 304822d268cbSEd Tanous } 30497f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 305022d268cbSEd Tanous { 30517f3e84a1SEd Tanous // Option currently returns no systems. TBD 30527f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30537f3e84a1SEd Tanous systemName); 30547f3e84a1SEd Tanous return; 30557f3e84a1SEd Tanous } 30567f3e84a1SEd Tanous if (systemName != "system") 30577f3e84a1SEd Tanous { 30587f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30597f3e84a1SEd Tanous systemName); 306022d268cbSEd Tanous return; 306122d268cbSEd Tanous } 306222d268cbSEd Tanous clearDump(asyncResp, "System"); 306322d268cbSEd Tanous } 306422d268cbSEd Tanous 3065fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 3066fdd26906SClaire Weinan { 3067fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 3068fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3069fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3070fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 3071fdd26906SClaire Weinan } 3072fdd26906SClaire Weinan 3073fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 3074fdd26906SClaire Weinan { 3075fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 3076fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3077fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3078fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 3079c9bb6861Sraviteja-b } 3080c9bb6861Sraviteja-b 30817e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 3082c9bb6861Sraviteja-b { 30837e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30847e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3085ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 3086fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3087fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 3088fdd26906SClaire Weinan 30897e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30907e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3091ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 3092fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3093fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 3094c9bb6861Sraviteja-b } 3095c9bb6861Sraviteja-b 3096168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 3097168d1b1aSCarson Labrado { 3098168d1b1aSCarson Labrado BMCWEB_ROUTE( 3099168d1b1aSCarson Labrado app, 31009e9d99daSRavi Teja "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/") 3101168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3102168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3103168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 3104168d1b1aSCarson Labrado } 3105168d1b1aSCarson Labrado 31067e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 3107c9bb6861Sraviteja-b { 31080fda0f12SGeorge Liu BMCWEB_ROUTE( 31090fda0f12SGeorge Liu app, 31100fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3111ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 31127e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 3113fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 3114fdd26906SClaire Weinan std::ref(app), "BMC")); 3115a43be80fSAsmitha Karunanithi } 3116a43be80fSAsmitha Karunanithi 31177e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 311880319af1SAsmitha Karunanithi { 31190fda0f12SGeorge Liu BMCWEB_ROUTE( 31200fda0f12SGeorge Liu app, 31210fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 3122ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 3123fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3124fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 312545ca1b86SEd Tanous } 3126fdd26906SClaire Weinan 3127168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 3128168d1b1aSCarson Labrado { 3129168d1b1aSCarson Labrado BMCWEB_ROUTE( 3130168d1b1aSCarson Labrado app, 31319e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 3132168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3133168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3134168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 3135168d1b1aSCarson Labrado } 3136168d1b1aSCarson Labrado 3137fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3138fdd26906SClaire Weinan { 3139fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 3140fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3141fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3142fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3143fdd26906SClaire Weinan } 3144fdd26906SClaire Weinan 3145fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3146fdd26906SClaire Weinan { 3147fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 3148fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3149fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3150fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3151fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3152fdd26906SClaire Weinan } 3153fdd26906SClaire Weinan 3154fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3155fdd26906SClaire Weinan { 3156fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3157fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3158fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3159fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3160fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3161fdd26906SClaire Weinan 3162fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3163fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3164fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3165fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3166fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3167fdd26906SClaire Weinan } 3168fdd26906SClaire Weinan 3169fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3170fdd26906SClaire Weinan { 3171fdd26906SClaire Weinan BMCWEB_ROUTE( 3172fdd26906SClaire Weinan app, 3173fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 3174fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3175fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3176fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 31775cb1dd27SAsmitha Karunanithi } 31785cb1dd27SAsmitha Karunanithi 31797e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 31805cb1dd27SAsmitha Karunanithi { 318122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3182ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 31836ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 318422d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 31855cb1dd27SAsmitha Karunanithi } 31865cb1dd27SAsmitha Karunanithi 31877e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 31887e860f15SJohn Edward Broadbent { 318922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3190ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 319122d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 319222d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 319322d268cbSEd Tanous std::ref(app))); 31945cb1dd27SAsmitha Karunanithi } 31955cb1dd27SAsmitha Karunanithi 31967e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 31975cb1dd27SAsmitha Karunanithi { 31987e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 319922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3200ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32016ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 320222d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 32038d1b46d7Szhanghch05 32047e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 320522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3206ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 32076ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 320822d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 32095cb1dd27SAsmitha Karunanithi } 3210c9bb6861Sraviteja-b 32117e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3212c9bb6861Sraviteja-b { 32130fda0f12SGeorge Liu BMCWEB_ROUTE( 32140fda0f12SGeorge Liu app, 321522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3216ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 321722d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 321822d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 321922d268cbSEd Tanous std::ref(app))); 3220a43be80fSAsmitha Karunanithi } 3221a43be80fSAsmitha Karunanithi 32227e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3223a43be80fSAsmitha Karunanithi { 32240fda0f12SGeorge Liu BMCWEB_ROUTE( 32250fda0f12SGeorge Liu app, 322622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3227ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 32286ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 322922d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3230013487e5Sraviteja-b } 3231013487e5Sraviteja-b 32327e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 32331da66f75SEd Tanous { 32343946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32353946028dSAppaRao Puli // method for security reasons. 32361da66f75SEd Tanous /** 32371da66f75SEd Tanous * Functions triggers appropriate requests on DBus 32381da66f75SEd Tanous */ 323922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3240ed398213SEd Tanous // This is incorrect, should be: 3241ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3242432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3243002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3244002d39b4SEd Tanous [&app](const crow::Request& req, 324522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324622d268cbSEd Tanous const std::string& systemName) { 32473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 324845ca1b86SEd Tanous { 324945ca1b86SEd Tanous return; 325045ca1b86SEd Tanous } 32517f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32527f3e84a1SEd Tanous { 32537f3e84a1SEd Tanous // Option currently returns no systems. TBD 32547f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32557f3e84a1SEd Tanous systemName); 32567f3e84a1SEd Tanous return; 32577f3e84a1SEd Tanous } 325822d268cbSEd Tanous if (systemName != "system") 325922d268cbSEd Tanous { 326022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 326122d268cbSEd Tanous systemName); 326222d268cbSEd Tanous return; 326322d268cbSEd Tanous } 326422d268cbSEd Tanous 32657e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 32667e860f15SJohn Edward Broadbent // SubRoute 32670f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3268424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3269e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32708e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 32714f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 32724f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 327315b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3274e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3275e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 32767c8c4058STejas Patil 32777c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 32782b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 32797c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 32807c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 32817c8c4058STejas Patil redfishDateTimeOffset.second; 32827c8c4058STejas Patil 32831476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3284ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3285002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 32861476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3287002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 32881476687dSEd Tanous ["target"] = 32891476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 32907e860f15SJohn Edward Broadbent }); 32911da66f75SEd Tanous } 32921da66f75SEd Tanous 32937e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 32945b61b5e8SJason M. Bills { 32950fda0f12SGeorge Liu BMCWEB_ROUTE( 32960fda0f12SGeorge Liu app, 329722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3298ed398213SEd Tanous // This is incorrect, should be: 3299ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3300432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 33017e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 330245ca1b86SEd Tanous [&app](const crow::Request& req, 330322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 330422d268cbSEd Tanous const std::string& systemName) { 33053ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 330645ca1b86SEd Tanous { 330745ca1b86SEd Tanous return; 330845ca1b86SEd Tanous } 33097f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 33107f3e84a1SEd Tanous { 33117f3e84a1SEd Tanous // Option currently returns no systems. TBD 33127f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33137f3e84a1SEd Tanous systemName); 33147f3e84a1SEd Tanous return; 33157f3e84a1SEd Tanous } 331622d268cbSEd Tanous if (systemName != "system") 331722d268cbSEd Tanous { 331822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 331922d268cbSEd Tanous systemName); 332022d268cbSEd Tanous return; 332122d268cbSEd Tanous } 33225b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 33235e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3324cb13a392SEd Tanous const std::string&) { 33255b61b5e8SJason M. Bills if (ec) 33265b61b5e8SJason M. Bills { 33275b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 33285b61b5e8SJason M. Bills return; 33295b61b5e8SJason M. Bills } 33305b61b5e8SJason M. Bills messages::success(asyncResp->res); 33315b61b5e8SJason M. Bills }, 3332002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 33337e860f15SJohn Edward Broadbent }); 33345b61b5e8SJason M. Bills } 33355b61b5e8SJason M. Bills 33368d1b46d7Szhanghch05 static void 33378d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 33388d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3339e855dd28SJason M. Bills { 3340043a0536SJohnathan Mantey auto getStoredLogCallback = 3341b9d36b47SEd Tanous [asyncResp, logID, 33425e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3343b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3344e855dd28SJason M. Bills if (ec) 3345e855dd28SJason M. Bills { 334662598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 33471ddcf01aSJason M. Bills if (ec.value() == 33481ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 33491ddcf01aSJason M. Bills { 3350002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33511ddcf01aSJason M. Bills } 33521ddcf01aSJason M. Bills else 33531ddcf01aSJason M. Bills { 3354e855dd28SJason M. Bills messages::internalError(asyncResp->res); 33551ddcf01aSJason M. Bills } 3356e855dd28SJason M. Bills return; 3357e855dd28SJason M. Bills } 3358043a0536SJohnathan Mantey 3359043a0536SJohnathan Mantey std::string timestamp{}; 3360043a0536SJohnathan Mantey std::string filename{}; 3361043a0536SJohnathan Mantey std::string logfile{}; 33622c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3363043a0536SJohnathan Mantey 3364043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3365e855dd28SJason M. Bills { 33669db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3367e855dd28SJason M. Bills return; 3368e855dd28SJason M. Bills } 3369e855dd28SJason M. Bills 3370043a0536SJohnathan Mantey std::string crashdumpURI = 3371e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3372043a0536SJohnathan Mantey logID + "/" + filename; 337384afc48bSJason M. Bills nlohmann::json::object_t logEntry; 33749c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3375ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3376ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3377ef4c65b7SEd Tanous logID); 337884afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 337984afc48bSJason M. Bills logEntry["Id"] = logID; 338084afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 338184afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 338284afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 338384afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 338484afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 33852b20ef6eSJason M. Bills 33862b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 33872b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 33882b20ef6eSJason M. Bills // directly 33892b20ef6eSJason M. Bills if (logEntryJson.is_array()) 33902b20ef6eSJason M. Bills { 33912b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 33922b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 33932b20ef6eSJason M. Bills logEntryJson.size(); 33942b20ef6eSJason M. Bills } 33952b20ef6eSJason M. Bills else 33962b20ef6eSJason M. Bills { 3397d405bb51SJason M. Bills logEntryJson.update(logEntry); 33982b20ef6eSJason M. Bills } 3399e855dd28SJason M. Bills }; 3400d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3401d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3402d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3403d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3404e855dd28SJason M. Bills } 3405e855dd28SJason M. Bills 34067e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 34071da66f75SEd Tanous { 34083946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34093946028dSAppaRao Puli // method for security reasons. 34101da66f75SEd Tanous /** 34111da66f75SEd Tanous * Functions triggers appropriate requests on DBus 34121da66f75SEd Tanous */ 34137e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 341422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3415ed398213SEd Tanous // This is incorrect, should be. 3416ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3417432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3418002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3419002d39b4SEd Tanous [&app](const crow::Request& req, 342022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 342122d268cbSEd Tanous const std::string& systemName) { 34223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 342345ca1b86SEd Tanous { 342445ca1b86SEd Tanous return; 342545ca1b86SEd Tanous } 34267f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34277f3e84a1SEd Tanous { 34287f3e84a1SEd Tanous // Option currently returns no systems. TBD 34297f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34307f3e84a1SEd Tanous systemName); 34317f3e84a1SEd Tanous return; 34327f3e84a1SEd Tanous } 343322d268cbSEd Tanous if (systemName != "system") 343422d268cbSEd Tanous { 343522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 343622d268cbSEd Tanous systemName); 343722d268cbSEd Tanous return; 343822d268cbSEd Tanous } 343922d268cbSEd Tanous 34407a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 34417a1dbc48SGeorge Liu crashdumpInterface}; 34427a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 34437a1dbc48SGeorge Liu "/", 0, interfaces, 34447a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 34452b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 34461da66f75SEd Tanous if (ec) 34471da66f75SEd Tanous { 34481da66f75SEd Tanous if (ec.value() != 34491da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 34501da66f75SEd Tanous { 345162598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 345262598e31SEd Tanous ec.message()); 3453f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34541da66f75SEd Tanous return; 34551da66f75SEd Tanous } 34561da66f75SEd Tanous } 3457e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 34581da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 34590f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3460424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3461002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3462e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3463424c4176SJason M. Bills "Collection of Crashdump Entries"; 3464002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3465a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 34662b20ef6eSJason M. Bills 34672b20ef6eSJason M. Bills for (const std::string& path : resp) 34681da66f75SEd Tanous { 34692b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3470e855dd28SJason M. Bills // Get the log ID 34712b20ef6eSJason M. Bills std::string logID = objPath.filename(); 34722b20ef6eSJason M. Bills if (logID.empty()) 34731da66f75SEd Tanous { 3474e855dd28SJason M. Bills continue; 34751da66f75SEd Tanous } 3476e855dd28SJason M. Bills // Add the log entry to the array 34772b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 34782b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 34791da66f75SEd Tanous } 34807a1dbc48SGeorge Liu }); 34817e860f15SJohn Edward Broadbent }); 34821da66f75SEd Tanous } 34831da66f75SEd Tanous 34847e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 34851da66f75SEd Tanous { 34863946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34873946028dSAppaRao Puli // method for security reasons. 34881da66f75SEd Tanous 34897e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 349022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3491ed398213SEd Tanous // this is incorrect, should be 3492ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3493432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 34947e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 349545ca1b86SEd Tanous [&app](const crow::Request& req, 34967e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 349722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 34983ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 349945ca1b86SEd Tanous { 350045ca1b86SEd Tanous return; 350145ca1b86SEd Tanous } 35027f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35037f3e84a1SEd Tanous { 35047f3e84a1SEd Tanous // Option currently returns no systems. TBD 35057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35067f3e84a1SEd Tanous systemName); 35077f3e84a1SEd Tanous return; 35087f3e84a1SEd Tanous } 350922d268cbSEd Tanous if (systemName != "system") 351022d268cbSEd Tanous { 351122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 351222d268cbSEd Tanous systemName); 351322d268cbSEd Tanous return; 351422d268cbSEd Tanous } 35157e860f15SJohn Edward Broadbent const std::string& logID = param; 3516e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 35177e860f15SJohn Edward Broadbent }); 3518e855dd28SJason M. Bills } 3519e855dd28SJason M. Bills 35207e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3521e855dd28SJason M. Bills { 35223946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 35233946028dSAppaRao Puli // method for security reasons. 35247e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 35257e860f15SJohn Edward Broadbent app, 352622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3527ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 35287e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3529a4ce114aSNan Zhou [](const crow::Request& req, 35307e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 353122d268cbSEd Tanous const std::string& systemName, const std::string& logID, 353222d268cbSEd Tanous const std::string& fileName) { 35332a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 35342a9beeedSShounak Mitra // Redfish resource. 353522d268cbSEd Tanous 35367f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35377f3e84a1SEd Tanous { 35387f3e84a1SEd Tanous // Option currently returns no systems. TBD 35397f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35407f3e84a1SEd Tanous systemName); 35417f3e84a1SEd Tanous return; 35427f3e84a1SEd Tanous } 354322d268cbSEd Tanous if (systemName != "system") 354422d268cbSEd Tanous { 354522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 354622d268cbSEd Tanous systemName); 354722d268cbSEd Tanous return; 354822d268cbSEd Tanous } 354922d268cbSEd Tanous 3550043a0536SJohnathan Mantey auto getStoredLogCallback = 355139662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 35525e7e2dc5SEd Tanous const boost::system::error_code& ec, 3553002d39b4SEd Tanous const std::vector< 3554002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 35557e860f15SJohn Edward Broadbent resp) { 35561da66f75SEd Tanous if (ec) 35571da66f75SEd Tanous { 355862598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3559f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35601da66f75SEd Tanous return; 35611da66f75SEd Tanous } 3562e855dd28SJason M. Bills 3563043a0536SJohnathan Mantey std::string dbusFilename{}; 3564043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3565043a0536SJohnathan Mantey std::string dbusFilepath{}; 3566043a0536SJohnathan Mantey 3567002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3568002d39b4SEd Tanous dbusFilepath); 3569043a0536SJohnathan Mantey 3570043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3571043a0536SJohnathan Mantey dbusFilepath.empty()) 35721da66f75SEd Tanous { 35739db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 35741da66f75SEd Tanous return; 35751da66f75SEd Tanous } 3576e855dd28SJason M. Bills 3577043a0536SJohnathan Mantey // Verify the file name parameter is correct 3578043a0536SJohnathan Mantey if (fileName != dbusFilename) 3579043a0536SJohnathan Mantey { 35809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3581043a0536SJohnathan Mantey return; 3582043a0536SJohnathan Mantey } 3583043a0536SJohnathan Mantey 358427b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3585043a0536SJohnathan Mantey { 35869db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3587043a0536SJohnathan Mantey return; 3588043a0536SJohnathan Mantey } 3589043a0536SJohnathan Mantey 35907e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 35917e860f15SJohn Edward Broadbent // from a browser 3592d9f6c621SEd Tanous asyncResp->res.addHeader( 3593d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 35941da66f75SEd Tanous }; 3595d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3596d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3597d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3598d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 35997e860f15SJohn Edward Broadbent }); 36001da66f75SEd Tanous } 36011da66f75SEd Tanous 3602c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3603c5a4c82aSJason M. Bills { 3604c5a4c82aSJason M. Bills onDemand, 3605c5a4c82aSJason M. Bills telemetry, 3606c5a4c82aSJason M. Bills invalid, 3607c5a4c82aSJason M. Bills }; 3608c5a4c82aSJason M. Bills 360926ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3610c5a4c82aSJason M. Bills { 3611c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3612c5a4c82aSJason M. Bills { 3613c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3614c5a4c82aSJason M. Bills } 3615c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3616c5a4c82aSJason M. Bills { 3617c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3618c5a4c82aSJason M. Bills } 3619c5a4c82aSJason M. Bills 3620c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3621c5a4c82aSJason M. Bills } 3622c5a4c82aSJason M. Bills 36237e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 36241da66f75SEd Tanous { 36253946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 36263946028dSAppaRao Puli // method for security reasons. 36270fda0f12SGeorge Liu BMCWEB_ROUTE( 36280fda0f12SGeorge Liu app, 362922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3630ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3631ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3632432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3633002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3634002d39b4SEd Tanous [&app](const crow::Request& req, 363522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 363622d268cbSEd Tanous const std::string& systemName) { 36373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 363845ca1b86SEd Tanous { 363945ca1b86SEd Tanous return; 364045ca1b86SEd Tanous } 364122d268cbSEd Tanous 36427f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 36437f3e84a1SEd Tanous { 36447f3e84a1SEd Tanous // Option currently returns no systems. TBD 36457f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36467f3e84a1SEd Tanous systemName); 36477f3e84a1SEd Tanous return; 36487f3e84a1SEd Tanous } 364922d268cbSEd Tanous if (systemName != "system") 365022d268cbSEd Tanous { 365122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 365222d268cbSEd Tanous systemName); 365322d268cbSEd Tanous return; 365422d268cbSEd Tanous } 365522d268cbSEd Tanous 36568e6c099aSJason M. Bills std::string diagnosticDataType; 36578e6c099aSJason M. Bills std::string oemDiagnosticDataType; 365815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3659002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3660002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 36618e6c099aSJason M. Bills { 36628e6c099aSJason M. Bills return; 36638e6c099aSJason M. Bills } 36648e6c099aSJason M. Bills 36658e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 36668e6c099aSJason M. Bills { 366762598e31SEd Tanous BMCWEB_LOG_ERROR( 366862598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 36698e6c099aSJason M. Bills messages::actionParameterValueFormatError( 36708e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 36718e6c099aSJason M. Bills "CollectDiagnosticData"); 36728e6c099aSJason M. Bills return; 36738e6c099aSJason M. Bills } 36748e6c099aSJason M. Bills 3675c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3676c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3677c5a4c82aSJason M. Bills 3678c5a4c82aSJason M. Bills std::string iface; 3679c5a4c82aSJason M. Bills std::string method; 3680c5a4c82aSJason M. Bills std::string taskMatchStr; 3681c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3682c5a4c82aSJason M. Bills { 3683c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3684c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3685c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3686c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3687c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3688c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3689c5a4c82aSJason M. Bills } 3690c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3691c5a4c82aSJason M. Bills { 3692c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3693c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3694c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3695c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3696c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3697c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3698c5a4c82aSJason M. Bills } 3699c5a4c82aSJason M. Bills else 3700c5a4c82aSJason M. Bills { 370162598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 370262598e31SEd Tanous oemDiagnosticDataType); 3703c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3704002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3705002d39b4SEd Tanous "CollectDiagnosticData"); 3706c5a4c82aSJason M. Bills return; 3707c5a4c82aSJason M. Bills } 3708c5a4c82aSJason M. Bills 3709c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3710c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 37115e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 371298be3e39SEd Tanous const std::string&) mutable { 37131da66f75SEd Tanous if (ec) 37141da66f75SEd Tanous { 3715002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 37161da66f75SEd Tanous { 3717f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 37181da66f75SEd Tanous } 37194363d3b2SJason M. Bills else if (ec.value() == 37204363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 37214363d3b2SJason M. Bills { 3722002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3723002d39b4SEd Tanous "60"); 37244363d3b2SJason M. Bills } 37251da66f75SEd Tanous else 37261da66f75SEd Tanous { 3727f12894f8SJason M. Bills messages::internalError(asyncResp->res); 37281da66f75SEd Tanous } 37291da66f75SEd Tanous return; 37301da66f75SEd Tanous } 3731002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 37328b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3733002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 37348b24275dSEd Tanous if (!ec2) 373566afe4faSJames Feist { 3736002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3737e5d5006bSJames Feist std::to_string(taskData->index))); 3738831d6b09SJames Feist taskData->state = "Completed"; 373966afe4faSJames Feist } 374032898ceaSJames Feist return task::completed; 374166afe4faSJames Feist }, 3742c5a4c82aSJason M. Bills taskMatchStr); 3743c5a4c82aSJason M. Bills 374446229577SJames Feist task->startTimer(std::chrono::minutes(5)); 374546229577SJames Feist task->populateResp(asyncResp->res); 374698be3e39SEd Tanous task->payload.emplace(std::move(payload)); 37471da66f75SEd Tanous }; 37488e6c099aSJason M. Bills 37491da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3750002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3751002d39b4SEd Tanous iface, method); 37527e860f15SJohn Edward Broadbent }); 37536eda7685SKenny L. Ku } 37546eda7685SKenny L. Ku 3755cb92c03bSAndrew Geissler /** 3756cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3757cb92c03bSAndrew Geissler */ 37587e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3759cb92c03bSAndrew Geissler { 3760cb92c03bSAndrew Geissler /** 3761cb92c03bSAndrew Geissler * Function handles POST method request. 3762cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3763cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3764cb92c03bSAndrew Geissler */ 37657e860f15SJohn Edward Broadbent 37660fda0f12SGeorge Liu BMCWEB_ROUTE( 37670fda0f12SGeorge Liu app, 376822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3769ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 37707e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 377145ca1b86SEd Tanous [&app](const crow::Request& req, 377222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 377322d268cbSEd Tanous const std::string& systemName) { 37743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 377545ca1b86SEd Tanous { 377645ca1b86SEd Tanous return; 377745ca1b86SEd Tanous } 37787f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37797f3e84a1SEd Tanous { 37807f3e84a1SEd Tanous // Option currently returns no systems. TBD 37817f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37827f3e84a1SEd Tanous systemName); 37837f3e84a1SEd Tanous return; 37847f3e84a1SEd Tanous } 378522d268cbSEd Tanous if (systemName != "system") 378622d268cbSEd Tanous { 378722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 378822d268cbSEd Tanous systemName); 378922d268cbSEd Tanous return; 379022d268cbSEd Tanous } 379162598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3792cb92c03bSAndrew Geissler 3793cb92c03bSAndrew Geissler // Process response from Logging service. 37945e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 379562598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3796cb92c03bSAndrew Geissler if (ec) 3797cb92c03bSAndrew Geissler { 3798cb92c03bSAndrew Geissler // TODO Handle for specific error code 379962598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3800cb92c03bSAndrew Geissler asyncResp->res.result( 3801cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3802cb92c03bSAndrew Geissler return; 3803cb92c03bSAndrew Geissler } 3804cb92c03bSAndrew Geissler 3805002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3806cb92c03bSAndrew Geissler }; 3807cb92c03bSAndrew Geissler 3808cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3809cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 38102c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3811cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3812cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 38137e860f15SJohn Edward Broadbent }); 3814cb92c03bSAndrew Geissler } 3815a3316fc6SZhikuiRen 3816a3316fc6SZhikuiRen /**************************************************** 3817a3316fc6SZhikuiRen * Redfish PostCode interfaces 3818a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3819a3316fc6SZhikuiRen ******************************************************/ 38207e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3821a3316fc6SZhikuiRen { 382222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3823ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3824002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3825002d39b4SEd Tanous [&app](const crow::Request& req, 382622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 382722d268cbSEd Tanous const std::string& systemName) { 38283ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 382945ca1b86SEd Tanous { 383045ca1b86SEd Tanous return; 383145ca1b86SEd Tanous } 38327f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38337f3e84a1SEd Tanous { 38347f3e84a1SEd Tanous // Option currently returns no systems. TBD 38357f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38367f3e84a1SEd Tanous systemName); 38377f3e84a1SEd Tanous return; 38387f3e84a1SEd Tanous } 383922d268cbSEd Tanous if (systemName != "system") 384022d268cbSEd Tanous { 384122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 384222d268cbSEd Tanous systemName); 384322d268cbSEd Tanous return; 384422d268cbSEd Tanous } 38451476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 38461476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 38471476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3848b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 38491476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 38501476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3851ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 38521476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 38531476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 38541476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 38557c8c4058STejas Patil 38567c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 38572b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 38580fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 38597c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 38607c8c4058STejas Patil redfishDateTimeOffset.second; 38617c8c4058STejas Patil 3862a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 38637e860f15SJohn Edward Broadbent {"target", 38640fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 38657e860f15SJohn Edward Broadbent }); 3866a3316fc6SZhikuiRen } 3867a3316fc6SZhikuiRen 38687e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3869a3316fc6SZhikuiRen { 38700fda0f12SGeorge Liu BMCWEB_ROUTE( 38710fda0f12SGeorge Liu app, 387222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3873ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3874ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3875432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 38767e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 387745ca1b86SEd Tanous [&app](const crow::Request& req, 387822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 387922d268cbSEd Tanous const std::string& systemName) { 38803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 388145ca1b86SEd Tanous { 388245ca1b86SEd Tanous return; 388345ca1b86SEd Tanous } 38847f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38857f3e84a1SEd Tanous { 38867f3e84a1SEd Tanous // Option currently returns no systems. TBD 38877f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38887f3e84a1SEd Tanous systemName); 38897f3e84a1SEd Tanous return; 38907f3e84a1SEd Tanous } 389122d268cbSEd Tanous if (systemName != "system") 389222d268cbSEd Tanous { 389322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 389422d268cbSEd Tanous systemName); 389522d268cbSEd Tanous return; 389622d268cbSEd Tanous } 389762598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3898a3316fc6SZhikuiRen 3899a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3900a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 39015e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3902a3316fc6SZhikuiRen if (ec) 3903a3316fc6SZhikuiRen { 3904a3316fc6SZhikuiRen // TODO Handle for specific error code 390562598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 390662598e31SEd Tanous ec); 3907002d39b4SEd Tanous asyncResp->res.result( 3908002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3909a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3910a3316fc6SZhikuiRen return; 3911a3316fc6SZhikuiRen } 391218fc70c0STony Lee messages::success(asyncResp->res); 3913a3316fc6SZhikuiRen }, 391415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 391515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3916a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 39177e860f15SJohn Edward Broadbent }); 3918a3316fc6SZhikuiRen } 3919a3316fc6SZhikuiRen 39206f284d24SJiaqing Zhao /** 39216f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 39226f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 39236f284d24SJiaqing Zhao * 39246f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 39256f284d24SJiaqing Zhao * @param[out] currentValue Current value 39266f284d24SJiaqing Zhao * @param[out] index Index value 39276f284d24SJiaqing Zhao * 39286f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 39296f284d24SJiaqing Zhao */ 39306f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 39316f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 39326f284d24SJiaqing Zhao { 39336f284d24SJiaqing Zhao std::vector<std::string> split; 393450ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 39356f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 39366f284d24SJiaqing Zhao { 39376f284d24SJiaqing Zhao return false; 39386f284d24SJiaqing Zhao } 39396f284d24SJiaqing Zhao 394084396af9SPatrick Williams auto start = std::next(split[0].begin()); 394184396af9SPatrick Williams auto end = split[0].end(); 394284396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 39436f284d24SJiaqing Zhao 394484396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 39456f284d24SJiaqing Zhao { 39466f284d24SJiaqing Zhao return false; 39476f284d24SJiaqing Zhao } 39486f284d24SJiaqing Zhao 394984396af9SPatrick Williams start = split[1].begin(); 395084396af9SPatrick Williams end = split[1].end(); 39516f284d24SJiaqing Zhao 395284396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 39536f284d24SJiaqing Zhao 395484396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 39556f284d24SJiaqing Zhao } 39566f284d24SJiaqing Zhao 39576f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3958ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39596c9a279eSManojkiran Eda const boost::container::flat_map< 39606c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3961a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3962a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3963a3316fc6SZhikuiRen { 3964a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3965fffb8c1fSEd Tanous const registries::Message* message = 3966fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3967a3316fc6SZhikuiRen 3968a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3969a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 39706c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 39716c9a279eSManojkiran Eda code : postcode) 3972a3316fc6SZhikuiRen { 3973a3316fc6SZhikuiRen currentCodeIndex++; 3974a3316fc6SZhikuiRen std::string postcodeEntryID = 3975a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3976a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3977a3316fc6SZhikuiRen 3978a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3979a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3980a3316fc6SZhikuiRen 3981a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3982a3316fc6SZhikuiRen { // already incremented 3983a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3984a3316fc6SZhikuiRen } 3985a3316fc6SZhikuiRen else 3986a3316fc6SZhikuiRen { 3987a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3988a3316fc6SZhikuiRen } 3989a3316fc6SZhikuiRen 3990a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3991a3316fc6SZhikuiRen // not fall between top and skip 3992a3316fc6SZhikuiRen if ((codeIndex == 0) && 3993a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3994a3316fc6SZhikuiRen { 3995a3316fc6SZhikuiRen continue; 3996a3316fc6SZhikuiRen } 3997a3316fc6SZhikuiRen 39984e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3999a3316fc6SZhikuiRen // currentIndex 4000a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 4001a3316fc6SZhikuiRen { 4002a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 4003a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 4004a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 4005a3316fc6SZhikuiRen continue; 4006a3316fc6SZhikuiRen } 4007a3316fc6SZhikuiRen 4008a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 4009a3316fc6SZhikuiRen // index 4010a3316fc6SZhikuiRen 4011a3316fc6SZhikuiRen // Get the Created time from the timestamp 4012a3316fc6SZhikuiRen std::string entryTimeStr; 40132a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 4014a3316fc6SZhikuiRen 4015a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 4016a3316fc6SZhikuiRen std::ostringstream hexCode; 4017a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 40186c9a279eSManojkiran Eda << std::get<0>(code.second); 4019a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 4020a3316fc6SZhikuiRen // Set Fixed -Point Notation 4021a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 4022a3316fc6SZhikuiRen // Set precision to 4 digits 4023a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 4024a3316fc6SZhikuiRen // Add double to stream 4025a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 4026a3316fc6SZhikuiRen 40271e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 40281e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 40291e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 4030a3316fc6SZhikuiRen 40311e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 40321e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 40331e6deaf6SEd Tanous 40341e6deaf6SEd Tanous std::string msg = 40351e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 40361e6deaf6SEd Tanous if (msg.empty()) 4037a3316fc6SZhikuiRen { 40381e6deaf6SEd Tanous messages::internalError(asyncResp->res); 40391e6deaf6SEd Tanous return false; 4040a3316fc6SZhikuiRen } 4041a3316fc6SZhikuiRen 4042d4342a92STim Lee // Get Severity template from message registry 4043d4342a92STim Lee std::string severity; 4044d4342a92STim Lee if (message != nullptr) 4045d4342a92STim Lee { 40465f2b84eeSEd Tanous severity = message->messageSeverity; 4047d4342a92STim Lee } 4048d4342a92STim Lee 40496f284d24SJiaqing Zhao // Format entry 40506f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 40519c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4052ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 4053ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 4054ef4c65b7SEd Tanous postcodeEntryID); 405584afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 405684afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 405784afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 405884afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 40591e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 406084afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 406184afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 406284afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 4063647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 4064647b3cdcSGeorge Liu { 4065647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 4066647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 4067647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 4068647b3cdcSGeorge Liu } 40696f284d24SJiaqing Zhao 40706f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 40716f284d24SJiaqing Zhao // that entry in this case 40726f284d24SJiaqing Zhao if (codeIndex != 0) 40736f284d24SJiaqing Zhao { 4074ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 40756f284d24SJiaqing Zhao return true; 4076a3316fc6SZhikuiRen } 40776f284d24SJiaqing Zhao 4078ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 4079b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 40806f284d24SJiaqing Zhao } 40816f284d24SJiaqing Zhao 40826f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 40836f284d24SJiaqing Zhao return false; 4084a3316fc6SZhikuiRen } 4085a3316fc6SZhikuiRen 4086ac106bf6SEd Tanous static void 4087ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40886f284d24SJiaqing Zhao const std::string& entryId) 4089a3316fc6SZhikuiRen { 40906f284d24SJiaqing Zhao uint16_t bootIndex = 0; 40916f284d24SJiaqing Zhao uint64_t codeIndex = 0; 40926f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 40936f284d24SJiaqing Zhao { 40946f284d24SJiaqing Zhao // Requested ID was not found 4095ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40966f284d24SJiaqing Zhao return; 40976f284d24SJiaqing Zhao } 40986f284d24SJiaqing Zhao 40996f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 41006f284d24SJiaqing Zhao { 41016f284d24SJiaqing Zhao // 0 is an invalid index 4102ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41036f284d24SJiaqing Zhao return; 41046f284d24SJiaqing Zhao } 41056f284d24SJiaqing Zhao 4106a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4107ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 41085e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 41096c9a279eSManojkiran Eda const boost::container::flat_map< 41106c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41116c9a279eSManojkiran Eda postcode) { 4112a3316fc6SZhikuiRen if (ec) 4113a3316fc6SZhikuiRen { 411462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4115ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4116a3316fc6SZhikuiRen return; 4117a3316fc6SZhikuiRen } 4118a3316fc6SZhikuiRen 4119a3316fc6SZhikuiRen if (postcode.empty()) 4120a3316fc6SZhikuiRen { 4121ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 4122a3316fc6SZhikuiRen return; 4123a3316fc6SZhikuiRen } 4124a3316fc6SZhikuiRen 4125ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 41266f284d24SJiaqing Zhao { 4127ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41286f284d24SJiaqing Zhao return; 41296f284d24SJiaqing Zhao } 4130a3316fc6SZhikuiRen }, 413115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 413215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4133a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4134a3316fc6SZhikuiRen bootIndex); 4135a3316fc6SZhikuiRen } 4136a3316fc6SZhikuiRen 4137ac106bf6SEd Tanous static void 4138ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4139ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4140ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4141a3316fc6SZhikuiRen { 4142a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4143ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 41445e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 41456c9a279eSManojkiran Eda const boost::container::flat_map< 41466c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41476c9a279eSManojkiran Eda postcode) { 4148a3316fc6SZhikuiRen if (ec) 4149a3316fc6SZhikuiRen { 415062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4151ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4152a3316fc6SZhikuiRen return; 4153a3316fc6SZhikuiRen } 4154a3316fc6SZhikuiRen 4155a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4156a3316fc6SZhikuiRen if (!postcode.empty()) 4157a3316fc6SZhikuiRen { 4158a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 41593648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4160a3316fc6SZhikuiRen { 416189492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 416289492a15SPatrick Williams entryCount) - 41633648c8beSEd Tanous entryCount; 4164a3316fc6SZhikuiRen uint64_t thisBootTop = 41653648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 41663648c8beSEd Tanous entryCount; 4167a3316fc6SZhikuiRen 4168ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4169ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4170a3316fc6SZhikuiRen } 4171ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4172a3316fc6SZhikuiRen } 4173a3316fc6SZhikuiRen 4174a3316fc6SZhikuiRen // continue to previous bootIndex 4175a3316fc6SZhikuiRen if (bootIndex < bootCount) 4176a3316fc6SZhikuiRen { 4177ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4178a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4179a3316fc6SZhikuiRen } 418081584abeSJiaqing Zhao else if (skip + top < endCount) 4181a3316fc6SZhikuiRen { 4182ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 41830fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 4184a3316fc6SZhikuiRen std::to_string(skip + top); 4185a3316fc6SZhikuiRen } 4186a3316fc6SZhikuiRen }, 418715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 418815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4189a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4190a3316fc6SZhikuiRen bootIndex); 4191a3316fc6SZhikuiRen } 4192a3316fc6SZhikuiRen 41938d1b46d7Szhanghch05 static void 4194ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 41953648c8beSEd Tanous size_t skip, size_t top) 4196a3316fc6SZhikuiRen { 4197a3316fc6SZhikuiRen uint64_t entryCount = 0; 41981e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 41991e1e598dSJonathan Doman *crow::connections::systemBus, 42001e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 42011e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 42021e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4203ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 42041e1e598dSJonathan Doman const uint16_t bootCount) { 4205a3316fc6SZhikuiRen if (ec) 4206a3316fc6SZhikuiRen { 420762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4208ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4209a3316fc6SZhikuiRen return; 4210a3316fc6SZhikuiRen } 4211ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 42121e1e598dSJonathan Doman }); 4213a3316fc6SZhikuiRen } 4214a3316fc6SZhikuiRen 42157e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4216a3316fc6SZhikuiRen { 42177e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 421822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4219ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 42207e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 422145ca1b86SEd Tanous [&app](const crow::Request& req, 422222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 422322d268cbSEd Tanous const std::string& systemName) { 4224c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4225c937d2bfSEd Tanous .canDelegateTop = true, 4226c937d2bfSEd Tanous .canDelegateSkip = true, 4227c937d2bfSEd Tanous }; 4228c937d2bfSEd Tanous query_param::Query delegatedQuery; 4229c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 42303ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 423145ca1b86SEd Tanous { 423245ca1b86SEd Tanous return; 423345ca1b86SEd Tanous } 42347f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42357f3e84a1SEd Tanous { 42367f3e84a1SEd Tanous // Option currently returns no systems. TBD 42377f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42387f3e84a1SEd Tanous systemName); 42397f3e84a1SEd Tanous return; 42407f3e84a1SEd Tanous } 424122d268cbSEd Tanous 424222d268cbSEd Tanous if (systemName != "system") 424322d268cbSEd Tanous { 424422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 424522d268cbSEd Tanous systemName); 424622d268cbSEd Tanous return; 424722d268cbSEd Tanous } 4248a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4249a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4250a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4251a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4252a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4253a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4254a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4255a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4256a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 42573648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 42585143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 42593648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 42607e860f15SJohn Edward Broadbent }); 4261a3316fc6SZhikuiRen } 4262a3316fc6SZhikuiRen 4263647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4264647b3cdcSGeorge Liu { 42650fda0f12SGeorge Liu BMCWEB_ROUTE( 42660fda0f12SGeorge Liu app, 426722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4268647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4269647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 427045ca1b86SEd Tanous [&app](const crow::Request& req, 4271647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 427222d268cbSEd Tanous const std::string& systemName, 4273647b3cdcSGeorge Liu const std::string& postCodeID) { 42743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 427545ca1b86SEd Tanous { 427645ca1b86SEd Tanous return; 427745ca1b86SEd Tanous } 427872e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 427999351cd8SEd Tanous req.getHeaderValue("Accept"), 42804a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4281647b3cdcSGeorge Liu { 4282002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4283647b3cdcSGeorge Liu return; 4284647b3cdcSGeorge Liu } 42857f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42867f3e84a1SEd Tanous { 42877f3e84a1SEd Tanous // Option currently returns no systems. TBD 42887f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42897f3e84a1SEd Tanous systemName); 42907f3e84a1SEd Tanous return; 42917f3e84a1SEd Tanous } 429222d268cbSEd Tanous if (systemName != "system") 429322d268cbSEd Tanous { 429422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 429522d268cbSEd Tanous systemName); 429622d268cbSEd Tanous return; 429722d268cbSEd Tanous } 4298647b3cdcSGeorge Liu 4299647b3cdcSGeorge Liu uint64_t currentValue = 0; 4300647b3cdcSGeorge Liu uint16_t index = 0; 4301647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4302647b3cdcSGeorge Liu { 4303002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4304647b3cdcSGeorge Liu return; 4305647b3cdcSGeorge Liu } 4306647b3cdcSGeorge Liu 4307647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4308647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 43095e7e2dc5SEd Tanous const boost::system::error_code& ec, 4310002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4311002d39b4SEd Tanous postcodes) { 4312647b3cdcSGeorge Liu if (ec.value() == EBADR) 4313647b3cdcSGeorge Liu { 4314002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4315002d39b4SEd Tanous postCodeID); 4316647b3cdcSGeorge Liu return; 4317647b3cdcSGeorge Liu } 4318647b3cdcSGeorge Liu if (ec) 4319647b3cdcSGeorge Liu { 432062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4321647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4322647b3cdcSGeorge Liu return; 4323647b3cdcSGeorge Liu } 4324647b3cdcSGeorge Liu 4325647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4326002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4327647b3cdcSGeorge Liu { 432862598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4329002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4330002d39b4SEd Tanous postCodeID); 4331647b3cdcSGeorge Liu return; 4332647b3cdcSGeorge Liu } 4333647b3cdcSGeorge Liu 43349eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 433546ff87baSEd Tanous if (c.empty()) 4336647b3cdcSGeorge Liu { 433762598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4338002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4339002d39b4SEd Tanous postCodeID); 4340647b3cdcSGeorge Liu return; 4341647b3cdcSGeorge Liu } 434246ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 434346ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 434446ff87baSEd Tanous std::string_view strData(d, c.size()); 4345647b3cdcSGeorge Liu 4346d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4347647b3cdcSGeorge Liu "application/octet-stream"); 4348d9f6c621SEd Tanous asyncResp->res.addHeader( 4349d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 435027b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4351647b3cdcSGeorge Liu }, 4352647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4353647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4354002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4355647b3cdcSGeorge Liu }); 4356647b3cdcSGeorge Liu } 4357647b3cdcSGeorge Liu 43587e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4359a3316fc6SZhikuiRen { 43607e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 436122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4362ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 43637e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 436445ca1b86SEd Tanous [&app](const crow::Request& req, 43657e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 436622d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 43673ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 436845ca1b86SEd Tanous { 436945ca1b86SEd Tanous return; 437045ca1b86SEd Tanous } 43717f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 43727f3e84a1SEd Tanous { 43737f3e84a1SEd Tanous // Option currently returns no systems. TBD 43747f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 43757f3e84a1SEd Tanous systemName); 43767f3e84a1SEd Tanous return; 43777f3e84a1SEd Tanous } 437822d268cbSEd Tanous if (systemName != "system") 437922d268cbSEd Tanous { 438022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 438122d268cbSEd Tanous systemName); 438222d268cbSEd Tanous return; 438322d268cbSEd Tanous } 438422d268cbSEd Tanous 43856f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 43867e860f15SJohn Edward Broadbent }); 4387a3316fc6SZhikuiRen } 4388a3316fc6SZhikuiRen 43891da66f75SEd Tanous } // namespace redfish 4390