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 34e1f26343SJason M. Bills #include <systemd/sd-journal.h> 358e31778eSAsmitha Karunanithi #include <tinyxml2.h> 36400fd1fbSAdriana Kobylak #include <unistd.h> 37e1f26343SJason M. Bills 389896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 3911ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 40400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 414851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 4207c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 431da66f75SEd Tanous #include <boost/container/flat_map.hpp> 441ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 45ef4c65b7SEd Tanous #include <boost/url/format.hpp> 46d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 47d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 481214b7e7SGunnar Mills 497a1dbc48SGeorge Liu #include <array> 50647b3cdcSGeorge Liu #include <charconv> 514418c7f0SJames Feist #include <filesystem> 5275710de2SXiaochao Ma #include <optional> 533544d2a7SEd Tanous #include <ranges> 5426702d01SEd Tanous #include <span> 55cd225da8SJason M. Bills #include <string_view> 56abf2add6SEd Tanous #include <variant> 571da66f75SEd Tanous 581da66f75SEd Tanous namespace redfish 591da66f75SEd Tanous { 601da66f75SEd Tanous 6189492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6289492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6389492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6489492a15SPatrick Williams constexpr const char* deleteAllInterface = 655b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6689492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 67424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6889492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 696eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 701da66f75SEd Tanous 718e31778eSAsmitha Karunanithi enum class DumpCreationProgress 728e31778eSAsmitha Karunanithi { 738e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 748e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 758e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 768e31778eSAsmitha Karunanithi }; 778e31778eSAsmitha Karunanithi 78f6150403SJames Feist namespace fs = std::filesystem; 791da66f75SEd Tanous 80cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 81cb92c03bSAndrew Geissler { 82d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 86cb92c03bSAndrew Geissler { 87cb92c03bSAndrew Geissler return "Critical"; 88cb92c03bSAndrew Geissler } 893174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 90d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 91d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 92cb92c03bSAndrew Geissler { 93cb92c03bSAndrew Geissler return "OK"; 94cb92c03bSAndrew Geissler } 953174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 96cb92c03bSAndrew Geissler { 97cb92c03bSAndrew Geissler return "Warning"; 98cb92c03bSAndrew Geissler } 99cb92c03bSAndrew Geissler return ""; 100cb92c03bSAndrew Geissler } 101cb92c03bSAndrew Geissler 1029017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1039017faf2SAbhishek Patel { 1049017faf2SAbhishek Patel std::optional<bool> notifyAction; 1059017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1069017faf2SAbhishek Patel { 1079017faf2SAbhishek Patel notifyAction = true; 1089017faf2SAbhishek Patel } 1099017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1109017faf2SAbhishek Patel { 1119017faf2SAbhishek Patel notifyAction = false; 1129017faf2SAbhishek Patel } 1139017faf2SAbhishek Patel 1149017faf2SAbhishek Patel return notifyAction; 1159017faf2SAbhishek Patel } 1169017faf2SAbhishek Patel 1177e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 11826ccae32SEd Tanous std::string_view field, 11939e77504SEd Tanous std::string_view& contents) 12016428a1aSJason M. Bills { 12116428a1aSJason M. Bills const char* data = nullptr; 12216428a1aSJason M. Bills size_t length = 0; 12316428a1aSJason M. Bills int ret = 0; 12416428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 12546ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 12646ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 12746ff87baSEd Tanous 12846ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 12916428a1aSJason M. Bills if (ret < 0) 13016428a1aSJason M. Bills { 13116428a1aSJason M. Bills return ret; 13216428a1aSJason M. Bills } 13339e77504SEd Tanous contents = std::string_view(data, length); 13416428a1aSJason M. Bills // Only use the content after the "=" character. 13581ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 13616428a1aSJason M. Bills return ret; 13716428a1aSJason M. Bills } 13816428a1aSJason M. Bills 1397e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 14026ccae32SEd Tanous std::string_view field, const int& base, 14126ccae32SEd Tanous long int& contents) 14216428a1aSJason M. Bills { 14316428a1aSJason M. Bills int ret = 0; 14439e77504SEd Tanous std::string_view metadata; 14516428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14616428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 14716428a1aSJason M. Bills if (ret < 0) 14816428a1aSJason M. Bills { 14916428a1aSJason M. Bills return ret; 15016428a1aSJason M. Bills } 151b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15216428a1aSJason M. Bills return ret; 15316428a1aSJason M. Bills } 15416428a1aSJason M. Bills 1557e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1567e860f15SJohn Edward Broadbent std::string& entryTimestamp) 157a3316fc6SZhikuiRen { 158a3316fc6SZhikuiRen int ret = 0; 159a3316fc6SZhikuiRen uint64_t timestamp = 0; 160a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 161a3316fc6SZhikuiRen if (ret < 0) 162a3316fc6SZhikuiRen { 16362598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 164a3316fc6SZhikuiRen return false; 165a3316fc6SZhikuiRen } 166e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1679c620e21SAsmitha Karunanithi return true; 168a3316fc6SZhikuiRen } 16950b8a43aSEd Tanous 1707e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 171e85d6b16SJason M. Bills const bool firstEntry = true) 17216428a1aSJason M. Bills { 17316428a1aSJason M. Bills int ret = 0; 17416428a1aSJason M. Bills static uint64_t prevTs = 0; 17516428a1aSJason M. Bills static int index = 0; 176e85d6b16SJason M. Bills if (firstEntry) 177e85d6b16SJason M. Bills { 178e85d6b16SJason M. Bills prevTs = 0; 179e85d6b16SJason M. Bills } 180e85d6b16SJason M. Bills 18116428a1aSJason M. Bills // Get the entry timestamp 18216428a1aSJason M. Bills uint64_t curTs = 0; 18316428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 18416428a1aSJason M. Bills if (ret < 0) 18516428a1aSJason M. Bills { 18662598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 18716428a1aSJason M. Bills return false; 18816428a1aSJason M. Bills } 18916428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 19016428a1aSJason M. Bills if (curTs == prevTs) 19116428a1aSJason M. Bills { 19216428a1aSJason M. Bills index++; 19316428a1aSJason M. Bills } 19416428a1aSJason M. Bills else 19516428a1aSJason M. Bills { 19616428a1aSJason M. Bills // Otherwise, reset it 19716428a1aSJason M. Bills index = 0; 19816428a1aSJason M. Bills } 19916428a1aSJason M. Bills // Save the timestamp 20016428a1aSJason M. Bills prevTs = curTs; 20116428a1aSJason M. Bills 20216428a1aSJason M. Bills entryID = std::to_string(curTs); 20316428a1aSJason M. Bills if (index > 0) 20416428a1aSJason M. Bills { 20516428a1aSJason M. Bills entryID += "_" + std::to_string(index); 20616428a1aSJason M. Bills } 20716428a1aSJason M. Bills return true; 20816428a1aSJason M. Bills } 20916428a1aSJason M. Bills 210e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 211e85d6b16SJason M. Bills const bool firstEntry = true) 21295820184SJason M. Bills { 213271584abSEd Tanous static time_t prevTs = 0; 21495820184SJason M. Bills static int index = 0; 215e85d6b16SJason M. Bills if (firstEntry) 216e85d6b16SJason M. Bills { 217e85d6b16SJason M. Bills prevTs = 0; 218e85d6b16SJason M. Bills } 219e85d6b16SJason M. Bills 22095820184SJason M. Bills // Get the entry timestamp 221271584abSEd Tanous std::time_t curTs = 0; 22295820184SJason M. Bills std::tm timeStruct = {}; 22395820184SJason M. Bills std::istringstream entryStream(logEntry); 22495820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 22595820184SJason M. Bills { 22695820184SJason M. Bills curTs = std::mktime(&timeStruct); 22795820184SJason M. Bills } 22895820184SJason M. Bills // If the timestamp isn't unique, increment the index 22995820184SJason M. Bills if (curTs == prevTs) 23095820184SJason M. Bills { 23195820184SJason M. Bills index++; 23295820184SJason M. Bills } 23395820184SJason M. Bills else 23495820184SJason M. Bills { 23595820184SJason M. Bills // Otherwise, reset it 23695820184SJason M. Bills index = 0; 23795820184SJason M. Bills } 23895820184SJason M. Bills // Save the timestamp 23995820184SJason M. Bills prevTs = curTs; 24095820184SJason M. Bills 24195820184SJason M. Bills entryID = std::to_string(curTs); 24295820184SJason M. Bills if (index > 0) 24395820184SJason M. Bills { 24495820184SJason M. Bills entryID += "_" + std::to_string(index); 24595820184SJason M. Bills } 24695820184SJason M. Bills return true; 24795820184SJason M. Bills } 24895820184SJason M. Bills 2497e860f15SJohn Edward Broadbent inline static bool 2508d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2518d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2528d1b46d7Szhanghch05 uint64_t& index) 25316428a1aSJason M. Bills { 25416428a1aSJason M. Bills if (entryID.empty()) 25516428a1aSJason M. Bills { 25616428a1aSJason M. Bills return false; 25716428a1aSJason M. Bills } 25816428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 25939e77504SEd Tanous std::string_view tsStr(entryID); 26016428a1aSJason M. Bills 26181ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 26271d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 26316428a1aSJason M. Bills { 26416428a1aSJason M. Bills // Timestamp has an index 26516428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 26639e77504SEd Tanous std::string_view indexStr(entryID); 26716428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 26884396af9SPatrick Williams auto [ptr, ec] = std::from_chars(indexStr.begin(), indexStr.end(), 26984396af9SPatrick Williams index); 270c0bd5e4bSEd Tanous if (ec != std::errc()) 27116428a1aSJason M. Bills { 2729db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 27316428a1aSJason M. Bills return false; 27416428a1aSJason M. Bills } 27516428a1aSJason M. Bills } 27616428a1aSJason M. Bills // Timestamp has no index 27784396af9SPatrick Williams auto [ptr, ec] = std::from_chars(tsStr.begin(), tsStr.end(), timestamp); 278c0bd5e4bSEd Tanous if (ec != std::errc()) 27916428a1aSJason M. Bills { 2809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 28116428a1aSJason M. Bills return false; 28216428a1aSJason M. Bills } 28316428a1aSJason M. Bills return true; 28416428a1aSJason M. Bills } 28516428a1aSJason M. Bills 28695820184SJason M. Bills static bool 28795820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 28895820184SJason M. Bills { 28995820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 29095820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 29195820184SJason M. Bills 29295820184SJason M. Bills // Loop through the directory looking for redfish log files 29395820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 29495820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 29595820184SJason M. Bills { 29695820184SJason M. Bills // If we find a redfish log file, save the path 29795820184SJason M. Bills std::string filename = dirEnt.path().filename(); 29811ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 29995820184SJason M. Bills { 30095820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 30195820184SJason M. Bills } 30295820184SJason M. Bills } 30395820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 30495820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 30595820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 3063544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 30795820184SJason M. Bills 30895820184SJason M. Bills return !redfishLogFiles.empty(); 30995820184SJason M. Bills } 31095820184SJason M. Bills 31168dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 31268dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 31368dd075aSAsmitha Karunanithi { 31468dd075aSAsmitha Karunanithi if (originatorType == 31568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 31668dd075aSAsmitha Karunanithi { 31768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 31868dd075aSAsmitha Karunanithi } 31968dd075aSAsmitha Karunanithi if (originatorType == 32068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 32168dd075aSAsmitha Karunanithi { 32268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 32368dd075aSAsmitha Karunanithi } 32468dd075aSAsmitha Karunanithi if (originatorType == 32568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 32668dd075aSAsmitha Karunanithi { 32768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 32868dd075aSAsmitha Karunanithi } 32968dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 33068dd075aSAsmitha Karunanithi } 33168dd075aSAsmitha Karunanithi 332aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3332d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 334c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 33568dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 336aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 337aefe3786SClaire Weinan { 338aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 339aefe3786SClaire Weinan { 340aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 341aefe3786SClaire Weinan { 342aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 343aefe3786SClaire Weinan { 344aefe3786SClaire Weinan if (propertyMap.first == "Status") 345aefe3786SClaire Weinan { 346aefe3786SClaire Weinan const auto* status = 347aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 348aefe3786SClaire Weinan if (status == nullptr) 349aefe3786SClaire Weinan { 350aefe3786SClaire Weinan messages::internalError(asyncResp->res); 351aefe3786SClaire Weinan break; 352aefe3786SClaire Weinan } 353aefe3786SClaire Weinan dumpStatus = *status; 354aefe3786SClaire Weinan } 355aefe3786SClaire Weinan } 356aefe3786SClaire Weinan } 357aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 358aefe3786SClaire Weinan { 359aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 360aefe3786SClaire Weinan { 361aefe3786SClaire Weinan if (propertyMap.first == "Size") 362aefe3786SClaire Weinan { 363aefe3786SClaire Weinan const auto* sizePtr = 364aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 365aefe3786SClaire Weinan if (sizePtr == nullptr) 366aefe3786SClaire Weinan { 367aefe3786SClaire Weinan messages::internalError(asyncResp->res); 368aefe3786SClaire Weinan break; 369aefe3786SClaire Weinan } 370aefe3786SClaire Weinan size = *sizePtr; 371aefe3786SClaire Weinan break; 372aefe3786SClaire Weinan } 373aefe3786SClaire Weinan } 374aefe3786SClaire Weinan } 375aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 376aefe3786SClaire Weinan { 377aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 378aefe3786SClaire Weinan { 379aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 380aefe3786SClaire Weinan { 381aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 382aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 383aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan messages::internalError(asyncResp->res); 386aefe3786SClaire Weinan break; 387aefe3786SClaire Weinan } 388c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 389aefe3786SClaire Weinan break; 390aefe3786SClaire Weinan } 391aefe3786SClaire Weinan } 392aefe3786SClaire Weinan } 39368dd075aSAsmitha Karunanithi else if (interfaceMap.first == 39468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 39568dd075aSAsmitha Karunanithi { 39668dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 39768dd075aSAsmitha Karunanithi { 39868dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 39968dd075aSAsmitha Karunanithi { 40068dd075aSAsmitha Karunanithi const std::string* id = 40168dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 40268dd075aSAsmitha Karunanithi if (id == nullptr) 40368dd075aSAsmitha Karunanithi { 40468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 40568dd075aSAsmitha Karunanithi break; 40668dd075aSAsmitha Karunanithi } 40768dd075aSAsmitha Karunanithi originatorId = *id; 40868dd075aSAsmitha Karunanithi } 40968dd075aSAsmitha Karunanithi 41068dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 41168dd075aSAsmitha Karunanithi { 41268dd075aSAsmitha Karunanithi const std::string* type = 41368dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 41468dd075aSAsmitha Karunanithi if (type == nullptr) 41568dd075aSAsmitha Karunanithi { 41668dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 41768dd075aSAsmitha Karunanithi break; 41868dd075aSAsmitha Karunanithi } 41968dd075aSAsmitha Karunanithi 42068dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 42168dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 42268dd075aSAsmitha Karunanithi { 42368dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 42468dd075aSAsmitha Karunanithi break; 42568dd075aSAsmitha Karunanithi } 42668dd075aSAsmitha Karunanithi } 42768dd075aSAsmitha Karunanithi } 42868dd075aSAsmitha Karunanithi } 429aefe3786SClaire Weinan } 430aefe3786SClaire Weinan } 431aefe3786SClaire Weinan 43221ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 433fdd26906SClaire Weinan { 434fdd26906SClaire Weinan std::string entriesPath; 435fdd26906SClaire Weinan 436fdd26906SClaire Weinan if (dumpType == "BMC") 437fdd26906SClaire Weinan { 438fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 439fdd26906SClaire Weinan } 440fdd26906SClaire Weinan else if (dumpType == "FaultLog") 441fdd26906SClaire Weinan { 442fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 443fdd26906SClaire Weinan } 444fdd26906SClaire Weinan else if (dumpType == "System") 445fdd26906SClaire Weinan { 446fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 447fdd26906SClaire Weinan } 448fdd26906SClaire Weinan else 449fdd26906SClaire Weinan { 45062598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 45162598e31SEd Tanous dumpType); 452fdd26906SClaire Weinan } 453fdd26906SClaire Weinan 454fdd26906SClaire Weinan // Returns empty string on error 455fdd26906SClaire Weinan return entriesPath; 456fdd26906SClaire Weinan } 457fdd26906SClaire Weinan 4588d1b46d7Szhanghch05 inline void 4598d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4605cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4615cb1dd27SAsmitha Karunanithi { 462fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 463fdd26906SClaire Weinan if (entriesPath.empty()) 4645cb1dd27SAsmitha Karunanithi { 4655cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4665cb1dd27SAsmitha Karunanithi return; 4675cb1dd27SAsmitha Karunanithi } 4685cb1dd27SAsmitha Karunanithi 4695eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4705eb468daSGeorge Liu dbus::utility::getManagedObjects( 4715eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 472fdd26906SClaire Weinan [asyncResp, entriesPath, 4735e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 4745eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 4755cb1dd27SAsmitha Karunanithi if (ec) 4765cb1dd27SAsmitha Karunanithi { 47762598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 4785cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4795cb1dd27SAsmitha Karunanithi return; 4805cb1dd27SAsmitha Karunanithi } 4815cb1dd27SAsmitha Karunanithi 482fdd26906SClaire Weinan // Remove ending slash 483fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 484fdd26906SClaire Weinan if (!odataIdStr.empty()) 485fdd26906SClaire Weinan { 486fdd26906SClaire Weinan odataIdStr.pop_back(); 487fdd26906SClaire Weinan } 488fdd26906SClaire Weinan 489fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 490fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 491fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 492fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 49389492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 49489492a15SPatrick Williams " Dump Entries"; 495fdd26906SClaire Weinan 4963544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 497b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 498b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 499002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 5005cb1dd27SAsmitha Karunanithi 5015eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 5023544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 503002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 504002d39b4SEd Tanous r.first.filename()); 505565dfb6fSClaire Weinan }); 506565dfb6fSClaire Weinan 5075cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5085cb1dd27SAsmitha Karunanithi { 509b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5105cb1dd27SAsmitha Karunanithi { 5115cb1dd27SAsmitha Karunanithi continue; 5125cb1dd27SAsmitha Karunanithi } 513c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5145cb1dd27SAsmitha Karunanithi uint64_t size = 0; 51535440d18SAsmitha Karunanithi std::string dumpStatus; 51668dd075aSAsmitha Karunanithi std::string originatorId; 51768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 51868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 519433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5202dfd18efSEd Tanous 5212dfd18efSEd Tanous std::string entryID = object.first.filename(); 5222dfd18efSEd Tanous if (entryID.empty()) 5235cb1dd27SAsmitha Karunanithi { 5245cb1dd27SAsmitha Karunanithi continue; 5255cb1dd27SAsmitha Karunanithi } 5265cb1dd27SAsmitha Karunanithi 527c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 52868dd075aSAsmitha Karunanithi originatorId, originatorType, 529aefe3786SClaire Weinan asyncResp); 5305cb1dd27SAsmitha Karunanithi 5310fda0f12SGeorge Liu if (dumpStatus != 5320fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 53335440d18SAsmitha Karunanithi !dumpStatus.empty()) 53435440d18SAsmitha Karunanithi { 53535440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 53635440d18SAsmitha Karunanithi continue; 53735440d18SAsmitha Karunanithi } 53835440d18SAsmitha Karunanithi 53968dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 540fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5415cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5425cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5435cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 544bbd80db8SClaire Weinan thisEntry["Created"] = 545bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5465cb1dd27SAsmitha Karunanithi 54768dd075aSAsmitha Karunanithi if (!originatorId.empty()) 54868dd075aSAsmitha Karunanithi { 54968dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 55068dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 55168dd075aSAsmitha Karunanithi } 55268dd075aSAsmitha Karunanithi 5535cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5545cb1dd27SAsmitha Karunanithi { 555d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 55689492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 55789492a15SPatrick Williams "/attachment"; 558fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5595cb1dd27SAsmitha Karunanithi } 5605cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5615cb1dd27SAsmitha Karunanithi { 562d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 563d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 56489492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 56589492a15SPatrick Williams "/attachment"; 566fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5675cb1dd27SAsmitha Karunanithi } 568b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 5695cb1dd27SAsmitha Karunanithi } 570002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5713544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 5725eb468daSGeorge Liu }); 5735cb1dd27SAsmitha Karunanithi } 5745cb1dd27SAsmitha Karunanithi 5758d1b46d7Szhanghch05 inline void 576c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5778d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5785cb1dd27SAsmitha Karunanithi { 579fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 580fdd26906SClaire Weinan if (entriesPath.empty()) 5815cb1dd27SAsmitha Karunanithi { 5825cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5835cb1dd27SAsmitha Karunanithi return; 5845cb1dd27SAsmitha Karunanithi } 5855cb1dd27SAsmitha Karunanithi 5865eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5875eb468daSGeorge Liu dbus::utility::getManagedObjects( 5885eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 589fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 5905e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 59102cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5925cb1dd27SAsmitha Karunanithi if (ec) 5935cb1dd27SAsmitha Karunanithi { 59462598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5955cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5965cb1dd27SAsmitha Karunanithi return; 5975cb1dd27SAsmitha Karunanithi } 5985cb1dd27SAsmitha Karunanithi 599b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 600b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 601b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 602002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 603b47452b2SAsmitha Karunanithi 6049eb808c1SEd Tanous for (const auto& objectPath : resp) 6055cb1dd27SAsmitha Karunanithi { 606b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6075cb1dd27SAsmitha Karunanithi { 6085cb1dd27SAsmitha Karunanithi continue; 6095cb1dd27SAsmitha Karunanithi } 6105cb1dd27SAsmitha Karunanithi 6115cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 612c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6135cb1dd27SAsmitha Karunanithi uint64_t size = 0; 61435440d18SAsmitha Karunanithi std::string dumpStatus; 61568dd075aSAsmitha Karunanithi std::string originatorId; 61668dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 61768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6185cb1dd27SAsmitha Karunanithi 619aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 62068dd075aSAsmitha Karunanithi timestampUs, originatorId, 62168dd075aSAsmitha Karunanithi originatorType, asyncResp); 6225cb1dd27SAsmitha Karunanithi 6230fda0f12SGeorge Liu if (dumpStatus != 6240fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 62535440d18SAsmitha Karunanithi !dumpStatus.empty()) 62635440d18SAsmitha Karunanithi { 62735440d18SAsmitha Karunanithi // Dump status is not Complete 62835440d18SAsmitha Karunanithi // return not found until status is changed to Completed 629d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 630d1bde9e5SKrzysztof Grobelny entryID); 63135440d18SAsmitha Karunanithi return; 63235440d18SAsmitha Karunanithi } 63335440d18SAsmitha Karunanithi 6345cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 63568dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 636fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6375cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6385cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6395cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 640bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 641bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6425cb1dd27SAsmitha Karunanithi 64368dd075aSAsmitha Karunanithi if (!originatorId.empty()) 64468dd075aSAsmitha Karunanithi { 64568dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 64668dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 64768dd075aSAsmitha Karunanithi } 64868dd075aSAsmitha Karunanithi 6495cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6505cb1dd27SAsmitha Karunanithi { 651d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 652d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 653fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 654fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6555cb1dd27SAsmitha Karunanithi } 6565cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6575cb1dd27SAsmitha Karunanithi { 658d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 659002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 660d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 661fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 662fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6635cb1dd27SAsmitha Karunanithi } 6645cb1dd27SAsmitha Karunanithi } 665e05aec50SEd Tanous if (!foundDumpEntry) 666b47452b2SAsmitha Karunanithi { 66762598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 668b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 669b90d14f2SMyung Bae entryID); 670b47452b2SAsmitha Karunanithi return; 671b47452b2SAsmitha Karunanithi } 6725eb468daSGeorge Liu }); 6735cb1dd27SAsmitha Karunanithi } 6745cb1dd27SAsmitha Karunanithi 6758d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6769878256fSStanley Chu const std::string& entryID, 677b47452b2SAsmitha Karunanithi const std::string& dumpType) 6785cb1dd27SAsmitha Karunanithi { 679*5a39f77aSPatrick Williams auto respHandler = [asyncResp, 680*5a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 68162598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 6825cb1dd27SAsmitha Karunanithi if (ec) 6835cb1dd27SAsmitha Karunanithi { 6843de8d8baSGeorge Liu if (ec.value() == EBADR) 6853de8d8baSGeorge Liu { 6863de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6873de8d8baSGeorge Liu return; 6883de8d8baSGeorge Liu } 68962598e31SEd Tanous BMCWEB_LOG_ERROR( 69062598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 69162598e31SEd Tanous entryID); 6925cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6935cb1dd27SAsmitha Karunanithi return; 6945cb1dd27SAsmitha Karunanithi } 6955cb1dd27SAsmitha Karunanithi }; 6965cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6975cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 698b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 699b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 700b47452b2SAsmitha Karunanithi entryID, 7015cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7025cb1dd27SAsmitha Karunanithi } 7035cb1dd27SAsmitha Karunanithi 704168d1b1aSCarson Labrado inline void 705168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 706168d1b1aSCarson Labrado const std::string& entryID, 707168d1b1aSCarson Labrado const std::string& downloadEntryType, 708168d1b1aSCarson Labrado const boost::system::error_code& ec, 709168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 710168d1b1aSCarson Labrado { 711168d1b1aSCarson Labrado if (ec.value() == EBADR) 712168d1b1aSCarson Labrado { 713168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 714168d1b1aSCarson Labrado return; 715168d1b1aSCarson Labrado } 716168d1b1aSCarson Labrado if (ec) 717168d1b1aSCarson Labrado { 718168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 719168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 720168d1b1aSCarson Labrado return; 721168d1b1aSCarson Labrado } 722168d1b1aSCarson Labrado 723168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 724168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 725168d1b1aSCarson Labrado { 726168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 727168d1b1aSCarson Labrado downloadEntryType); 728168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 729168d1b1aSCarson Labrado } 730168d1b1aSCarson Labrado 731168d1b1aSCarson Labrado int fd = -1; 732168d1b1aSCarson Labrado fd = dup(unixfd); 733168d1b1aSCarson Labrado if (fd < 0) 734168d1b1aSCarson Labrado { 735168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 736168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 737168d1b1aSCarson Labrado return; 738168d1b1aSCarson Labrado } 739168d1b1aSCarson Labrado 740168d1b1aSCarson Labrado long long int size = lseek(fd, 0, SEEK_END); 741168d1b1aSCarson Labrado if (size <= 0) 742168d1b1aSCarson Labrado { 743168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 744168d1b1aSCarson Labrado size); 745168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 746168d1b1aSCarson Labrado close(fd); 747168d1b1aSCarson Labrado return; 748168d1b1aSCarson Labrado } 749168d1b1aSCarson Labrado 750168d1b1aSCarson Labrado // Arbitrary max size of 20MB to accommodate BMC dumps 751168d1b1aSCarson Labrado constexpr int maxFileSize = 20 * 1024 * 1024; 752168d1b1aSCarson Labrado if (size > maxFileSize) 753168d1b1aSCarson Labrado { 754168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 755168d1b1aSCarson Labrado size, maxFileSize); 756168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 757168d1b1aSCarson Labrado close(fd); 758168d1b1aSCarson Labrado return; 759168d1b1aSCarson Labrado } 760168d1b1aSCarson Labrado long long int rc = lseek(fd, 0, SEEK_SET); 761168d1b1aSCarson Labrado if (rc < 0) 762168d1b1aSCarson Labrado { 763168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 764168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 765168d1b1aSCarson Labrado close(fd); 766168d1b1aSCarson Labrado return; 767168d1b1aSCarson Labrado } 768168d1b1aSCarson Labrado 769168d1b1aSCarson Labrado asyncResp->res.body().resize(static_cast<size_t>(size), '\0'); 770168d1b1aSCarson Labrado rc = read(fd, asyncResp->res.body().data(), asyncResp->res.body().size()); 771168d1b1aSCarson Labrado if ((rc == -1) || (rc != size)) 772168d1b1aSCarson Labrado { 773168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to read in file"); 774168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 775168d1b1aSCarson Labrado close(fd); 776168d1b1aSCarson Labrado return; 777168d1b1aSCarson Labrado } 778168d1b1aSCarson Labrado close(fd); 779168d1b1aSCarson Labrado 780168d1b1aSCarson Labrado if (downloadEntryType == "System") 781168d1b1aSCarson Labrado { 782168d1b1aSCarson Labrado // We need to encode the data. Doing it this way saves the other paths 783168d1b1aSCarson Labrado // from having to make a copy into a temporary variable. 784168d1b1aSCarson Labrado asyncResp->res.body() = 785168d1b1aSCarson Labrado crow::utility::base64encode(asyncResp->res.body()); 786168d1b1aSCarson Labrado asyncResp->res.addHeader( 787168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 788168d1b1aSCarson Labrado } 789168d1b1aSCarson Labrado 790168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 791168d1b1aSCarson Labrado "application/octet-stream"); 792168d1b1aSCarson Labrado } 793168d1b1aSCarson Labrado 794168d1b1aSCarson Labrado inline void 795168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 796168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 797168d1b1aSCarson Labrado { 798168d1b1aSCarson Labrado if (dumpType != "BMC") 799168d1b1aSCarson Labrado { 800168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 801168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 802168d1b1aSCarson Labrado return; 803168d1b1aSCarson Labrado } 804168d1b1aSCarson Labrado 805168d1b1aSCarson Labrado std::string dumpEntryPath = 806168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/dump/") / 807168d1b1aSCarson Labrado std::string(boost::algorithm::to_lower_copy(dumpType)) / "entry" / 808168d1b1aSCarson Labrado entryID; 809168d1b1aSCarson Labrado 810168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 811168d1b1aSCarson Labrado [asyncResp, entryID, 812168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 813168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 814168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 815168d1b1aSCarson Labrado }; 816168d1b1aSCarson Labrado 817168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 818168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 819168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 820168d1b1aSCarson Labrado } 821168d1b1aSCarson Labrado 822168d1b1aSCarson Labrado inline void 823168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 824168d1b1aSCarson Labrado const std::string& systemName, 825168d1b1aSCarson Labrado const std::string& entryID, 826168d1b1aSCarson Labrado const std::string& dumpType) 827168d1b1aSCarson Labrado { 828168d1b1aSCarson Labrado if constexpr (bmcwebEnableMultiHost) 829168d1b1aSCarson Labrado { 830168d1b1aSCarson Labrado // Option currently returns no systems. TBD 831168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 832168d1b1aSCarson Labrado systemName); 833168d1b1aSCarson Labrado return; 834168d1b1aSCarson Labrado } 835168d1b1aSCarson Labrado if (systemName != "system") 836168d1b1aSCarson Labrado { 837168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 838168d1b1aSCarson Labrado systemName); 839168d1b1aSCarson Labrado return; 840168d1b1aSCarson Labrado } 841168d1b1aSCarson Labrado 842168d1b1aSCarson Labrado std::string entryPath = 843168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 844168d1b1aSCarson Labrado entryID; 845168d1b1aSCarson Labrado 846168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 847168d1b1aSCarson Labrado [asyncResp, entryID, 848168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 849168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 850168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 851168d1b1aSCarson Labrado }; 852168d1b1aSCarson Labrado 853168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 854168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 855168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 856168d1b1aSCarson Labrado } 857168d1b1aSCarson Labrado 8588e31778eSAsmitha Karunanithi inline DumpCreationProgress 8598e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 860a43be80fSAsmitha Karunanithi { 8618e31778eSAsmitha Karunanithi if (status == 8628e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 8638e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 8648e31778eSAsmitha Karunanithi { 8658e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 8668e31778eSAsmitha Karunanithi } 8678e31778eSAsmitha Karunanithi if (status == 8688e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 8698e31778eSAsmitha Karunanithi { 8708e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 8718e31778eSAsmitha Karunanithi } 8728e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 8738e31778eSAsmitha Karunanithi } 8748e31778eSAsmitha Karunanithi 8758e31778eSAsmitha Karunanithi inline DumpCreationProgress 8768e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 8778e31778eSAsmitha Karunanithi { 8788e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 8798e31778eSAsmitha Karunanithi { 8808e31778eSAsmitha Karunanithi if (key == "Status") 8818e31778eSAsmitha Karunanithi { 8828e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 8838e31778eSAsmitha Karunanithi if (value == nullptr) 8848e31778eSAsmitha Karunanithi { 88562598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 8868e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 8878e31778eSAsmitha Karunanithi } 8888e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 8898e31778eSAsmitha Karunanithi } 8908e31778eSAsmitha Karunanithi } 8918e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 8928e31778eSAsmitha Karunanithi } 8938e31778eSAsmitha Karunanithi 8948e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 8958e31778eSAsmitha Karunanithi { 8968e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 8978e31778eSAsmitha Karunanithi { 8988e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 8998e31778eSAsmitha Karunanithi } 9008e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 9018e31778eSAsmitha Karunanithi { 9028e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 9038e31778eSAsmitha Karunanithi } 9048e31778eSAsmitha Karunanithi return ""; 9058e31778eSAsmitha Karunanithi } 9068e31778eSAsmitha Karunanithi 9078e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 9088e31778eSAsmitha Karunanithi task::Payload&& payload, 9098e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9108e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 9118e31778eSAsmitha Karunanithi { 9128e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 9138e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 9148e31778eSAsmitha Karunanithi 9158e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 9168e31778eSAsmitha Karunanithi 9178e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 9188e31778eSAsmitha Karunanithi { 91962598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 9208e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9218e31778eSAsmitha Karunanithi return; 9228e31778eSAsmitha Karunanithi } 9238e31778eSAsmitha Karunanithi 9248e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9258e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 9268e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 9275e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 9288e31778eSAsmitha Karunanithi const std::string& introspectXml) { 9298e31778eSAsmitha Karunanithi if (ec) 9308e31778eSAsmitha Karunanithi { 93162598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 93262598e31SEd Tanous ec.message()); 9338e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9348e31778eSAsmitha Karunanithi return; 9358e31778eSAsmitha Karunanithi } 9368e31778eSAsmitha Karunanithi 9378e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 9388e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 9398e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 9408e31778eSAsmitha Karunanithi // Else, return task completed. 9418e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 9428e31778eSAsmitha Karunanithi 9438e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 9448e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 9458e31778eSAsmitha Karunanithi if (pRoot == nullptr) 9468e31778eSAsmitha Karunanithi { 94762598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 9488e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9498e31778eSAsmitha Karunanithi return; 9508e31778eSAsmitha Karunanithi } 9518e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 9528e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 9538e31778eSAsmitha Karunanithi 9548e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 9558e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 9568e31778eSAsmitha Karunanithi { 9578e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 9588e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 9598e31778eSAsmitha Karunanithi { 9608e31778eSAsmitha Karunanithi if (thisInterfaceName == 9618e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 9628e31778eSAsmitha Karunanithi { 9638e31778eSAsmitha Karunanithi interfaceNode = 9648e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 9658e31778eSAsmitha Karunanithi continue; 9668e31778eSAsmitha Karunanithi } 9678e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 9688e31778eSAsmitha Karunanithi break; 9698e31778eSAsmitha Karunanithi } 9708e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 9718e31778eSAsmitha Karunanithi } 9728e31778eSAsmitha Karunanithi 973a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 9748e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 9758b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 976a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 9778b24275dSEd Tanous if (ec2) 978cb13a392SEd Tanous { 97962598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 98062598e31SEd Tanous createdObjPath.str); 9818e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 9826145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 9836145ed6fSAsmitha Karunanithi return task::completed; 984cb13a392SEd Tanous } 985b9d36b47SEd Tanous 9868e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 987a43be80fSAsmitha Karunanithi { 9888e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 9898e31778eSAsmitha Karunanithi std::string prop; 9908e31778eSAsmitha Karunanithi msg.read(prop, values); 9918e31778eSAsmitha Karunanithi 9928e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 9938e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 9948e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 9958e31778eSAsmitha Karunanithi { 99662598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 99762598e31SEd Tanous createdObjPath.str); 9988e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 9998e31778eSAsmitha Karunanithi return task::completed; 10008e31778eSAsmitha Karunanithi } 10018e31778eSAsmitha Karunanithi 10028e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 10038e31778eSAsmitha Karunanithi { 100462598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 100562598e31SEd Tanous createdObjPath.str); 10068e31778eSAsmitha Karunanithi return !task::completed; 10078e31778eSAsmitha Karunanithi } 10088e31778eSAsmitha Karunanithi } 10098e31778eSAsmitha Karunanithi 1010a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 1011a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 1012a43be80fSAsmitha Karunanithi 1013c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 1014c51a58eeSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId); 1015c51a58eeSEd Tanous 1016c51a58eeSEd Tanous std::string headerLoc = "Location: "; 1017c51a58eeSEd Tanous headerLoc += url.buffer(); 1018c51a58eeSEd Tanous 1019002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 1020a43be80fSAsmitha Karunanithi 102162598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 102262598e31SEd Tanous createdObjPath.str); 1023a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 1024b47452b2SAsmitha Karunanithi return task::completed; 1025a43be80fSAsmitha Karunanithi }, 10268e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 10278e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 10288e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 1029a43be80fSAsmitha Karunanithi 10308e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 10318e31778eSAsmitha Karunanithi // requested dump will be collected. 10328e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 1033a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 10348e31778eSAsmitha Karunanithi task->payload.emplace(payload); 10358e31778eSAsmitha Karunanithi }, 10368e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 10378e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 1038a43be80fSAsmitha Karunanithi } 1039a43be80fSAsmitha Karunanithi 10408d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10418d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 1042a43be80fSAsmitha Karunanithi { 1043fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 1044fdd26906SClaire Weinan if (dumpPath.empty()) 1045a43be80fSAsmitha Karunanithi { 1046a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1047a43be80fSAsmitha Karunanithi return; 1048a43be80fSAsmitha Karunanithi } 1049a43be80fSAsmitha Karunanithi 1050a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 1051a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 1052a43be80fSAsmitha Karunanithi 105315ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 1054a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 1055a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 1056a43be80fSAsmitha Karunanithi { 1057a43be80fSAsmitha Karunanithi return; 1058a43be80fSAsmitha Karunanithi } 1059a43be80fSAsmitha Karunanithi 1060a43be80fSAsmitha Karunanithi if (dumpType == "System") 1061a43be80fSAsmitha Karunanithi { 1062a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 1063a43be80fSAsmitha Karunanithi { 106462598e31SEd Tanous BMCWEB_LOG_ERROR( 106562598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 1066a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1067a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 1068a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 1069a43be80fSAsmitha Karunanithi return; 1070a43be80fSAsmitha Karunanithi } 10713174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 1072a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 1073a43be80fSAsmitha Karunanithi { 107462598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 1075ace85d60SEd Tanous messages::internalError(asyncResp->res); 1076a43be80fSAsmitha Karunanithi return; 1077a43be80fSAsmitha Karunanithi } 10785907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 1079a43be80fSAsmitha Karunanithi } 1080a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 1081a43be80fSAsmitha Karunanithi { 1082a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 1083a43be80fSAsmitha Karunanithi { 108462598e31SEd Tanous BMCWEB_LOG_ERROR( 108562598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 1086a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1087a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 1088a43be80fSAsmitha Karunanithi return; 1089a43be80fSAsmitha Karunanithi } 10903174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 1091a43be80fSAsmitha Karunanithi { 109262598e31SEd Tanous BMCWEB_LOG_ERROR( 109362598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 1094ace85d60SEd Tanous messages::internalError(asyncResp->res); 1095a43be80fSAsmitha Karunanithi return; 1096a43be80fSAsmitha Karunanithi } 10975907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 10985907571dSAsmitha Karunanithi } 10995907571dSAsmitha Karunanithi else 11005907571dSAsmitha Karunanithi { 110162598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 11025907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11035907571dSAsmitha Karunanithi return; 1104a43be80fSAsmitha Karunanithi } 1105a43be80fSAsmitha Karunanithi 11068e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 11078e31778eSAsmitha Karunanithi createDumpParamVec; 11088e31778eSAsmitha Karunanithi 1109f574a8e1SCarson Labrado if (req.session != nullptr) 1110f574a8e1SCarson Labrado { 111168dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 111268dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 111368dd075aSAsmitha Karunanithi req.session->clientIp); 111468dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 111568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 111668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1117f574a8e1SCarson Labrado } 111868dd075aSAsmitha Karunanithi 1119a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 11205e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 11215e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 11225e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 11238e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1124a43be80fSAsmitha Karunanithi if (ec) 1125a43be80fSAsmitha Karunanithi { 112662598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 11275907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 11285907571dSAsmitha Karunanithi if (dbusError == nullptr) 11295907571dSAsmitha Karunanithi { 11305907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11315907571dSAsmitha Karunanithi return; 11325907571dSAsmitha Karunanithi } 11335907571dSAsmitha Karunanithi 113462598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 113562598e31SEd Tanous dbusError->name, dbusError->message); 11365907571dSAsmitha Karunanithi if (std::string_view( 11375907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 11385907571dSAsmitha Karunanithi dbusError->name) 11395907571dSAsmitha Karunanithi { 11405907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 11415907571dSAsmitha Karunanithi return; 11425907571dSAsmitha Karunanithi } 11435907571dSAsmitha Karunanithi if (std::string_view( 11445907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 11455907571dSAsmitha Karunanithi dbusError->name) 11465907571dSAsmitha Karunanithi { 11475907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 11485907571dSAsmitha Karunanithi return; 11495907571dSAsmitha Karunanithi } 11505907571dSAsmitha Karunanithi if (std::string_view( 11515907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 11525907571dSAsmitha Karunanithi dbusError->name) 11535907571dSAsmitha Karunanithi { 11545907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 11555907571dSAsmitha Karunanithi return; 11565907571dSAsmitha Karunanithi } 11575907571dSAsmitha Karunanithi // Other Dbus errors such as: 11585907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 11595907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 11605907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 11615907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 11625907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 11635907571dSAsmitha Karunanithi // back to the client. 1164a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1165a43be80fSAsmitha Karunanithi return; 1166a43be80fSAsmitha Karunanithi } 116762598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 11688e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1169a43be80fSAsmitha Karunanithi }, 1170b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 1171b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 1172b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 11738e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1174a43be80fSAsmitha Karunanithi } 1175a43be80fSAsmitha Karunanithi 11768d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11778d1b46d7Szhanghch05 const std::string& dumpType) 117880319af1SAsmitha Karunanithi { 1179b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 1180b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 11818d1b46d7Szhanghch05 11820d946211SClaire Weinan crow::connections::systemBus->async_method_call( 11830d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 118480319af1SAsmitha Karunanithi if (ec) 118580319af1SAsmitha Karunanithi { 118662598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 118780319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 118880319af1SAsmitha Karunanithi return; 118980319af1SAsmitha Karunanithi } 11900d946211SClaire Weinan }, 11910d946211SClaire Weinan "xyz.openbmc_project.Dump.Manager", 11920d946211SClaire Weinan "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 11930d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 119480319af1SAsmitha Karunanithi } 119580319af1SAsmitha Karunanithi 1196b9d36b47SEd Tanous inline static void 1197b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1198b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1199b9d36b47SEd Tanous std::string& logfile) 1200043a0536SJohnathan Mantey { 1201d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1202d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1203d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1204d1bde9e5SKrzysztof Grobelny 1205d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1206d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1207d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1208d1bde9e5SKrzysztof Grobelny 1209d1bde9e5SKrzysztof Grobelny if (!success) 1210043a0536SJohnathan Mantey { 1211d1bde9e5SKrzysztof Grobelny return; 1212043a0536SJohnathan Mantey } 1213d1bde9e5SKrzysztof Grobelny 1214d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1215043a0536SJohnathan Mantey { 1216d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1217d1bde9e5SKrzysztof Grobelny } 1218d1bde9e5SKrzysztof Grobelny 1219d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1220043a0536SJohnathan Mantey { 1221d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1222043a0536SJohnathan Mantey } 1223d1bde9e5SKrzysztof Grobelny 1224d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1225043a0536SJohnathan Mantey { 1226d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1227043a0536SJohnathan Mantey } 1228043a0536SJohnathan Mantey } 1229043a0536SJohnathan Mantey 12307e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 12311da66f75SEd Tanous { 1232c4bf6374SJason M. Bills /** 1233c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1234c4bf6374SJason M. Bills */ 123522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1236ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1237002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1238002d39b4SEd Tanous [&app](const crow::Request& req, 123922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 124022d268cbSEd Tanous const std::string& systemName) { 12413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1242c4bf6374SJason M. Bills { 124345ca1b86SEd Tanous return; 124445ca1b86SEd Tanous } 12457f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 12467f3e84a1SEd Tanous { 12477f3e84a1SEd Tanous // Option currently returns no systems. TBD 12487f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 12497f3e84a1SEd Tanous systemName); 12507f3e84a1SEd Tanous return; 12517f3e84a1SEd Tanous } 125222d268cbSEd Tanous if (systemName != "system") 125322d268cbSEd Tanous { 125422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 125522d268cbSEd Tanous systemName); 125622d268cbSEd Tanous return; 125722d268cbSEd Tanous } 125822d268cbSEd Tanous 12597e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 12607e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1261c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1262c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1263c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1264029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 126545ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1266c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1267c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1268002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1269c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 12701476687dSEd Tanous nlohmann::json::object_t eventLog; 12711476687dSEd Tanous eventLog["@odata.id"] = 12721476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1273b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 12745cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 12751476687dSEd Tanous nlohmann::json::object_t dumpLog; 1276002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1277b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1278c9bb6861Sraviteja-b #endif 1279c9bb6861Sraviteja-b 1280d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 12811476687dSEd Tanous nlohmann::json::object_t crashdump; 12821476687dSEd Tanous crashdump["@odata.id"] = 12831476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1284b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1285d53dd41fSJason M. Bills #endif 1286b7028ebfSSpencer Ku 1287b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 12881476687dSEd Tanous nlohmann::json::object_t hostlogger; 12891476687dSEd Tanous hostlogger["@odata.id"] = 12901476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1291b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1292b7028ebfSSpencer Ku #endif 1293c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1294c4bf6374SJason M. Bills logServiceArray.size(); 1295a3316fc6SZhikuiRen 12967a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 12977a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 12987a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 12997a1dbc48SGeorge Liu "/", 0, interfaces, 13007a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1301b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1302b9d36b47SEd Tanous subtreePath) { 1303a3316fc6SZhikuiRen if (ec) 1304a3316fc6SZhikuiRen { 130562598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1306a3316fc6SZhikuiRen return; 1307a3316fc6SZhikuiRen } 1308a3316fc6SZhikuiRen 130955f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1310a3316fc6SZhikuiRen { 1311a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1312a3316fc6SZhikuiRen { 131323a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1314a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1315613dabeaSEd Tanous nlohmann::json::object_t member; 1316613dabeaSEd Tanous member["@odata.id"] = 1317613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1318613dabeaSEd Tanous 1319b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1320613dabeaSEd Tanous 132145ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 132223a21a1cSEd Tanous logServiceArrayLocal.size(); 1323a3316fc6SZhikuiRen return; 1324a3316fc6SZhikuiRen } 1325a3316fc6SZhikuiRen } 13267a1dbc48SGeorge Liu }); 13277e860f15SJohn Edward Broadbent }); 1328c4bf6374SJason M. Bills } 1329c4bf6374SJason M. Bills 13307e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1331c4bf6374SJason M. Bills { 133222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1333ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1334002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1335002d39b4SEd Tanous [&app](const crow::Request& req, 133622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 133722d268cbSEd Tanous const std::string& systemName) { 13383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 133945ca1b86SEd Tanous { 134045ca1b86SEd Tanous return; 134145ca1b86SEd Tanous } 134222d268cbSEd Tanous if (systemName != "system") 134322d268cbSEd Tanous { 134422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 134522d268cbSEd Tanous systemName); 134622d268cbSEd Tanous return; 134722d268cbSEd Tanous } 1348c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1349029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1350c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1351b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1352c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1353002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1354c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1355c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 13567c8c4058STejas Patil 13577c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 13582b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 13597c8c4058STejas Patil 13607c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 13617c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 13627c8c4058STejas Patil redfishDateTimeOffset.second; 13637c8c4058STejas Patil 13641476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 13651476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1366e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1367e7d6c8b2SGunnar Mills 13680fda0f12SGeorge Liu {"target", 13690fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 13707e860f15SJohn Edward Broadbent }); 1371489640c6SJason M. Bills } 1372489640c6SJason M. Bills 13737e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1374489640c6SJason M. Bills { 13754978b63fSJason M. Bills BMCWEB_ROUTE( 13764978b63fSJason M. Bills app, 137722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1378432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 13797e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 138045ca1b86SEd Tanous [&app](const crow::Request& req, 138122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 138222d268cbSEd Tanous const std::string& systemName) { 13833ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 138445ca1b86SEd Tanous { 138545ca1b86SEd Tanous return; 138645ca1b86SEd Tanous } 138722d268cbSEd Tanous if (systemName != "system") 138822d268cbSEd Tanous { 138922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 139022d268cbSEd Tanous systemName); 139122d268cbSEd Tanous return; 139222d268cbSEd Tanous } 1393489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1394489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1395489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1396489640c6SJason M. Bills { 1397489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1398489640c6SJason M. Bills { 1399489640c6SJason M. Bills std::error_code ec; 1400489640c6SJason M. Bills std::filesystem::remove(file, ec); 1401489640c6SJason M. Bills } 1402489640c6SJason M. Bills } 1403489640c6SJason M. Bills 1404489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1405489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 14065e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1407489640c6SJason M. Bills if (ec) 1408489640c6SJason M. Bills { 140962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1410489640c6SJason M. Bills messages::internalError(asyncResp->res); 1411489640c6SJason M. Bills return; 1412489640c6SJason M. Bills } 1413489640c6SJason M. Bills 1414489640c6SJason M. Bills messages::success(asyncResp->res); 1415489640c6SJason M. Bills }, 1416489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1417002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1418002d39b4SEd Tanous "replace"); 14197e860f15SJohn Edward Broadbent }); 1420c4bf6374SJason M. Bills } 1421c4bf6374SJason M. Bills 1422ac992cdeSJason M. Bills enum class LogParseError 1423ac992cdeSJason M. Bills { 1424ac992cdeSJason M. Bills success, 1425ac992cdeSJason M. Bills parseFailed, 1426ac992cdeSJason M. Bills messageIdNotInRegistry, 1427ac992cdeSJason M. Bills }; 1428ac992cdeSJason M. Bills 1429ac992cdeSJason M. Bills static LogParseError 1430ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1431b5a76932SEd Tanous const std::string& logEntry, 1432de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1433c4bf6374SJason M. Bills { 143495820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1435cd225da8SJason M. Bills // First get the Timestamp 1436f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1437cd225da8SJason M. Bills if (space == std::string::npos) 143895820184SJason M. Bills { 1439ac992cdeSJason M. Bills return LogParseError::parseFailed; 144095820184SJason M. Bills } 1441cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1442cd225da8SJason M. Bills // Then get the log contents 1443f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1444cd225da8SJason M. Bills if (entryStart == std::string::npos) 1445cd225da8SJason M. Bills { 1446ac992cdeSJason M. Bills return LogParseError::parseFailed; 1447cd225da8SJason M. Bills } 1448cd225da8SJason M. Bills std::string_view entry(logEntry); 1449cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1450cd225da8SJason M. Bills // Use split to separate the entry into its fields 1451cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 145250ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1453cd225da8SJason M. Bills // We need at least a MessageId to be valid 14541e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 14551e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1456cd225da8SJason M. Bills { 1457ac992cdeSJason M. Bills return LogParseError::parseFailed; 1458cd225da8SJason M. Bills } 14591e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 14604851d45dSJason M. Bills // Get the Message from the MessageRegistry 1461fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1462c4bf6374SJason M. Bills 14631e6deaf6SEd Tanous logEntryIter++; 146454417b02SSui Chen if (message == nullptr) 1465c4bf6374SJason M. Bills { 146662598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1467ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1468c4bf6374SJason M. Bills } 1469c4bf6374SJason M. Bills 14701e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 14711e6deaf6SEd Tanous logEntryFields.end()); 1472c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1473c05bba45SEd Tanous 14741e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 14751e6deaf6SEd Tanous message->message); 14761e6deaf6SEd Tanous if (msg.empty()) 147715a86ff6SJason M. Bills { 14781e6deaf6SEd Tanous return LogParseError::parseFailed; 147915a86ff6SJason M. Bills } 14804851d45dSJason M. Bills 148195820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 148295820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 148395820184SJason M. Bills // between the '.' and the '+', so just remove them. 1484f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1485f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 148695820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1487c4bf6374SJason M. Bills { 148895820184SJason M. Bills timestamp.erase(dot, plus - dot); 1489c4bf6374SJason M. Bills } 1490c4bf6374SJason M. Bills 1491c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 14929c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1493ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1494ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1495ef4c65b7SEd Tanous logEntryID); 149684afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 149784afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 149884afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 149984afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 150084afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 150184afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 150284afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 150384afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1504ac992cdeSJason M. Bills return LogParseError::success; 1505c4bf6374SJason M. Bills } 1506c4bf6374SJason M. Bills 15077e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1508c4bf6374SJason M. Bills { 150922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 15108b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1511002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1512002d39b4SEd Tanous [&app](const crow::Request& req, 151322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 151422d268cbSEd Tanous const std::string& systemName) { 1515c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1516c937d2bfSEd Tanous .canDelegateTop = true, 1517c937d2bfSEd Tanous .canDelegateSkip = true, 1518c937d2bfSEd Tanous }; 1519c937d2bfSEd Tanous query_param::Query delegatedQuery; 1520c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 15213ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1522c4bf6374SJason M. Bills { 1523c4bf6374SJason M. Bills return; 1524c4bf6374SJason M. Bills } 15257f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 15267f3e84a1SEd Tanous { 15277f3e84a1SEd Tanous // Option currently returns no systems. TBD 15287f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15297f3e84a1SEd Tanous systemName); 15307f3e84a1SEd Tanous return; 15317f3e84a1SEd Tanous } 153222d268cbSEd Tanous if (systemName != "system") 153322d268cbSEd Tanous { 153422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 153522d268cbSEd Tanous systemName); 153622d268cbSEd Tanous return; 153722d268cbSEd Tanous } 153822d268cbSEd Tanous 15395143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15403648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 15413648c8beSEd Tanous 15427e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15437e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1544c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1545c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1546c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1547029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1548c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1549c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1550c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1551cb92c03bSAndrew Geissler 15524978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1553c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 15547e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 15557e860f15SJohn Edward Broadbent // entry 155695820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 155795820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1558b01bf299SEd Tanous uint64_t entryCount = 0; 1559cd225da8SJason M. Bills std::string logEntry; 156095820184SJason M. Bills 15617e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15627e860f15SJohn Edward Broadbent // backwards 1563002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1564002d39b4SEd Tanous it++) 1565c4bf6374SJason M. Bills { 1566cd225da8SJason M. Bills std::ifstream logStream(*it); 156795820184SJason M. Bills if (!logStream.is_open()) 1568c4bf6374SJason M. Bills { 1569c4bf6374SJason M. Bills continue; 1570c4bf6374SJason M. Bills } 1571c4bf6374SJason M. Bills 1572e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1573e85d6b16SJason M. Bills bool firstEntry = true; 157495820184SJason M. Bills while (std::getline(logStream, logEntry)) 157595820184SJason M. Bills { 1576c4bf6374SJason M. Bills std::string idStr; 1577e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1578c4bf6374SJason M. Bills { 1579c4bf6374SJason M. Bills continue; 1580c4bf6374SJason M. Bills } 1581e85d6b16SJason M. Bills firstEntry = false; 1582e85d6b16SJason M. Bills 1583de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 158489492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 158589492a15SPatrick Williams bmcLogEntry); 1586ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1587ac992cdeSJason M. Bills { 1588ac992cdeSJason M. Bills continue; 1589ac992cdeSJason M. Bills } 1590ac992cdeSJason M. Bills if (status != LogParseError::success) 1591c4bf6374SJason M. Bills { 1592c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1593c4bf6374SJason M. Bills return; 1594c4bf6374SJason M. Bills } 1595de703c5dSJason M. Bills 1596de703c5dSJason M. Bills entryCount++; 1597de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1598de703c5dSJason M. Bills // start) and top (number of entries to display) 15993648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1600de703c5dSJason M. Bills { 1601de703c5dSJason M. Bills continue; 1602de703c5dSJason M. Bills } 1603de703c5dSJason M. Bills 1604b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1605c4bf6374SJason M. Bills } 160695820184SJason M. Bills } 1607c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16083648c8beSEd Tanous if (skip + top < entryCount) 1609c4bf6374SJason M. Bills { 1610c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 16114978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 16123648c8beSEd Tanous std::to_string(skip + top); 1613c4bf6374SJason M. Bills } 16147e860f15SJohn Edward Broadbent }); 1615897967deSJason M. Bills } 1616897967deSJason M. Bills 16177e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1618897967deSJason M. Bills { 16197e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 162022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1621ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 16227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 162345ca1b86SEd Tanous [&app](const crow::Request& req, 16247e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 162522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 162745ca1b86SEd Tanous { 162845ca1b86SEd Tanous return; 162945ca1b86SEd Tanous } 16307f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 16317f3e84a1SEd Tanous { 16327f3e84a1SEd Tanous // Option currently returns no systems. TBD 16337f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16347f3e84a1SEd Tanous systemName); 16357f3e84a1SEd Tanous return; 16367f3e84a1SEd Tanous } 163722d268cbSEd Tanous 163822d268cbSEd Tanous if (systemName != "system") 163922d268cbSEd Tanous { 164022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 164122d268cbSEd Tanous systemName); 164222d268cbSEd Tanous return; 164322d268cbSEd Tanous } 164422d268cbSEd Tanous 16457e860f15SJohn Edward Broadbent const std::string& targetID = param; 16468d1b46d7Szhanghch05 16477e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 16487e860f15SJohn Edward Broadbent // entry to find the target entry 1649897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1650897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1651897967deSJason M. Bills std::string logEntry; 1652897967deSJason M. Bills 16537e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16547e860f15SJohn Edward Broadbent // backwards 1655002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1656002d39b4SEd Tanous it++) 1657897967deSJason M. Bills { 1658897967deSJason M. Bills std::ifstream logStream(*it); 1659897967deSJason M. Bills if (!logStream.is_open()) 1660897967deSJason M. Bills { 1661897967deSJason M. Bills continue; 1662897967deSJason M. Bills } 1663897967deSJason M. Bills 1664897967deSJason M. Bills // Reset the unique ID on the first entry 1665897967deSJason M. Bills bool firstEntry = true; 1666897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1667897967deSJason M. Bills { 1668897967deSJason M. Bills std::string idStr; 1669897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1670897967deSJason M. Bills { 1671897967deSJason M. Bills continue; 1672897967deSJason M. Bills } 1673897967deSJason M. Bills firstEntry = false; 1674897967deSJason M. Bills 1675897967deSJason M. Bills if (idStr == targetID) 1676897967deSJason M. Bills { 1677de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1678ac992cdeSJason M. Bills LogParseError status = 1679ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1680ac992cdeSJason M. Bills if (status != LogParseError::success) 1681897967deSJason M. Bills { 1682897967deSJason M. Bills messages::internalError(asyncResp->res); 1683897967deSJason M. Bills return; 1684897967deSJason M. Bills } 1685d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1686897967deSJason M. Bills return; 1687897967deSJason M. Bills } 1688897967deSJason M. Bills } 1689897967deSJason M. Bills } 1690897967deSJason M. Bills // Requested ID was not found 16919db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 16927e860f15SJohn Edward Broadbent }); 169308a4e4b5SAnthony Wilson } 169408a4e4b5SAnthony Wilson 16957e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 169608a4e4b5SAnthony Wilson { 169722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1698ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1699002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1700002d39b4SEd Tanous [&app](const crow::Request& req, 170122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 170222d268cbSEd Tanous const std::string& systemName) { 17033ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 170445ca1b86SEd Tanous { 170545ca1b86SEd Tanous return; 170645ca1b86SEd Tanous } 17077f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 17087f3e84a1SEd Tanous { 17097f3e84a1SEd Tanous // Option currently returns no systems. TBD 17107f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17117f3e84a1SEd Tanous systemName); 17127f3e84a1SEd Tanous return; 17137f3e84a1SEd Tanous } 171422d268cbSEd Tanous if (systemName != "system") 171522d268cbSEd Tanous { 171622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 171722d268cbSEd Tanous systemName); 171822d268cbSEd Tanous return; 171922d268cbSEd Tanous } 172022d268cbSEd Tanous 17217e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 17227e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 172308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 172408a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 172508a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 172608a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 172708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 172808a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 172908a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 173008a4e4b5SAnthony Wilson 1731cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1732cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 17335eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 17345eb468daSGeorge Liu dbus::utility::getManagedObjects( 17355eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 17365e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1737914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1738cb92c03bSAndrew Geissler if (ec) 1739cb92c03bSAndrew Geissler { 1740cb92c03bSAndrew Geissler // TODO Handle for specific error code 174162598e31SEd Tanous BMCWEB_LOG_ERROR( 174262598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1743cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1744cb92c03bSAndrew Geissler return; 1745cb92c03bSAndrew Geissler } 17463544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 17479eb808c1SEd Tanous for (const auto& objectPath : resp) 1748cb92c03bSAndrew Geissler { 1749914e2d5dSEd Tanous const uint32_t* id = nullptr; 1750c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1751c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1752914e2d5dSEd Tanous const std::string* severity = nullptr; 1753914e2d5dSEd Tanous const std::string* message = nullptr; 1754914e2d5dSEd Tanous const std::string* filePath = nullptr; 17559c11a172SVijay Lobo const std::string* resolution = nullptr; 175675710de2SXiaochao Ma bool resolved = false; 17579017faf2SAbhishek Patel const std::string* notify = nullptr; 17589017faf2SAbhishek Patel 17599eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1760f86bb901SAdriana Kobylak { 1761f86bb901SAdriana Kobylak if (interfaceMap.first == 1762f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1763f86bb901SAdriana Kobylak { 1764002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1765cb92c03bSAndrew Geissler { 1766cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1767cb92c03bSAndrew Geissler { 1768002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1769cb92c03bSAndrew Geissler } 1770cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1771cb92c03bSAndrew Geissler { 1772002d39b4SEd Tanous timestamp = 1773002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 17747e860f15SJohn Edward Broadbent } 1775002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 17767e860f15SJohn Edward Broadbent { 1777002d39b4SEd Tanous updateTimestamp = 1778002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 17797e860f15SJohn Edward Broadbent } 17807e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 17817e860f15SJohn Edward Broadbent { 17827e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 17837e860f15SJohn Edward Broadbent &propertyMap.second); 17847e860f15SJohn Edward Broadbent } 17859c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 17869c11a172SVijay Lobo { 17879c11a172SVijay Lobo resolution = std::get_if<std::string>( 17889c11a172SVijay Lobo &propertyMap.second); 17899c11a172SVijay Lobo } 17907e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 17917e860f15SJohn Edward Broadbent { 17927e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 17937e860f15SJohn Edward Broadbent &propertyMap.second); 17947e860f15SJohn Edward Broadbent } 17957e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 17967e860f15SJohn Edward Broadbent { 1797914e2d5dSEd Tanous const bool* resolveptr = 1798002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 17997e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 18007e860f15SJohn Edward Broadbent { 1801002d39b4SEd Tanous messages::internalError(asyncResp->res); 18027e860f15SJohn Edward Broadbent return; 18037e860f15SJohn Edward Broadbent } 18047e860f15SJohn Edward Broadbent resolved = *resolveptr; 18057e860f15SJohn Edward Broadbent } 18069017faf2SAbhishek Patel else if (propertyMap.first == 18079017faf2SAbhishek Patel "ServiceProviderNotify") 18089017faf2SAbhishek Patel { 18099017faf2SAbhishek Patel notify = std::get_if<std::string>( 18109017faf2SAbhishek Patel &propertyMap.second); 18119017faf2SAbhishek Patel if (notify == nullptr) 18129017faf2SAbhishek Patel { 18139017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18149017faf2SAbhishek Patel return; 18159017faf2SAbhishek Patel } 18169017faf2SAbhishek Patel } 18177e860f15SJohn Edward Broadbent } 18187e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 18197e860f15SJohn Edward Broadbent severity == nullptr) 18207e860f15SJohn Edward Broadbent { 18217e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18227e860f15SJohn Edward Broadbent return; 18237e860f15SJohn Edward Broadbent } 18247e860f15SJohn Edward Broadbent } 18257e860f15SJohn Edward Broadbent else if (interfaceMap.first == 18267e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 18277e860f15SJohn Edward Broadbent { 1828002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 18297e860f15SJohn Edward Broadbent { 18307e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 18317e860f15SJohn Edward Broadbent { 18327e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 18337e860f15SJohn Edward Broadbent &propertyMap.second); 18347e860f15SJohn Edward Broadbent } 18357e860f15SJohn Edward Broadbent } 18367e860f15SJohn Edward Broadbent } 18377e860f15SJohn Edward Broadbent } 18387e860f15SJohn Edward Broadbent // Object path without the 18397e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 18407e860f15SJohn Edward Broadbent // and continue. 18417e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1842c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1843c419c759SEd Tanous updateTimestamp == nullptr) 18447e860f15SJohn Edward Broadbent { 18457e860f15SJohn Edward Broadbent continue; 18467e860f15SJohn Edward Broadbent } 18473544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 18489c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1849ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1850ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1851ef4c65b7SEd Tanous std::to_string(*id)); 18527e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 18537e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 18547e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 18557e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 18569c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18579c11a172SVijay Lobo { 18589c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 18599c11a172SVijay Lobo } 18609017faf2SAbhishek Patel std::optional<bool> notifyAction = 18619017faf2SAbhishek Patel getProviderNotifyAction(*notify); 18629017faf2SAbhishek Patel if (notifyAction) 18639017faf2SAbhishek Patel { 18649017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 18659017faf2SAbhishek Patel } 18667e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 18677e860f15SJohn Edward Broadbent thisEntry["Severity"] = 18687e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 18697e860f15SJohn Edward Broadbent thisEntry["Created"] = 18702b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 18717e860f15SJohn Edward Broadbent thisEntry["Modified"] = 18722b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 18737e860f15SJohn Edward Broadbent if (filePath != nullptr) 18747e860f15SJohn Edward Broadbent { 18757e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 18760fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 18777e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 18787e860f15SJohn Edward Broadbent } 18797e860f15SJohn Edward Broadbent } 18803544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 18813544d2a7SEd Tanous const nlohmann::json& right) { 18827e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 18837e860f15SJohn Edward Broadbent }); 18847e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 18857e860f15SJohn Edward Broadbent entriesArray.size(); 18863544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 18875eb468daSGeorge Liu }); 18887e860f15SJohn Edward Broadbent }); 18897e860f15SJohn Edward Broadbent } 18907e860f15SJohn Edward Broadbent 18917e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 18927e860f15SJohn Edward Broadbent { 18937e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 189422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1895ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1896002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1897002d39b4SEd Tanous [&app](const crow::Request& req, 18987e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 189922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19017e860f15SJohn Edward Broadbent { 190245ca1b86SEd Tanous return; 190345ca1b86SEd Tanous } 19047f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19057f3e84a1SEd Tanous { 19067f3e84a1SEd Tanous // Option currently returns no systems. TBD 19077f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19087f3e84a1SEd Tanous systemName); 19097f3e84a1SEd Tanous return; 19107f3e84a1SEd Tanous } 191122d268cbSEd Tanous if (systemName != "system") 191222d268cbSEd Tanous { 191322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 191422d268cbSEd Tanous systemName); 191522d268cbSEd Tanous return; 191622d268cbSEd Tanous } 191722d268cbSEd Tanous 19187e860f15SJohn Edward Broadbent std::string entryID = param; 19197e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 19207e860f15SJohn Edward Broadbent 19217e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 19227e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1923d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1924d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1925d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 19265e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1927b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 19287e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 19297e860f15SJohn Edward Broadbent { 1930d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1931d1bde9e5SKrzysztof Grobelny entryID); 19327e860f15SJohn Edward Broadbent return; 19337e860f15SJohn Edward Broadbent } 19347e860f15SJohn Edward Broadbent if (ec) 19357e860f15SJohn Edward Broadbent { 193662598e31SEd Tanous BMCWEB_LOG_ERROR( 193762598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 19387e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 19397e860f15SJohn Edward Broadbent return; 19407e860f15SJohn Edward Broadbent } 1941914e2d5dSEd Tanous const uint32_t* id = nullptr; 1942c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1943c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1944914e2d5dSEd Tanous const std::string* severity = nullptr; 1945914e2d5dSEd Tanous const std::string* message = nullptr; 1946914e2d5dSEd Tanous const std::string* filePath = nullptr; 19479c11a172SVijay Lobo const std::string* resolution = nullptr; 19487e860f15SJohn Edward Broadbent bool resolved = false; 19499017faf2SAbhishek Patel const std::string* notify = nullptr; 19507e860f15SJohn Edward Broadbent 1951d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1952d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1953d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 19549c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 19559017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 19569017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1957d1bde9e5SKrzysztof Grobelny 1958d1bde9e5SKrzysztof Grobelny if (!success) 195975710de2SXiaochao Ma { 196075710de2SXiaochao Ma messages::internalError(asyncResp->res); 196175710de2SXiaochao Ma return; 196275710de2SXiaochao Ma } 1963d1bde9e5SKrzysztof Grobelny 1964002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 19659017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 19669017faf2SAbhishek Patel notify == nullptr) 1967f86bb901SAdriana Kobylak { 1968ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1969271584abSEd Tanous return; 1970271584abSEd Tanous } 19719017faf2SAbhishek Patel 1972f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 19739c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1974ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1975ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1976ef4c65b7SEd Tanous std::to_string(*id)); 197745ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1978f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1979f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1980f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 19819017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 19829017faf2SAbhishek Patel if (notifyAction) 19839017faf2SAbhishek Patel { 19849017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 19859017faf2SAbhishek Patel *notifyAction; 19869017faf2SAbhishek Patel } 19879c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 19889c11a172SVijay Lobo { 19899c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 19909c11a172SVijay Lobo } 1991f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1992f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1993f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1994f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 19952b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1996f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 19972b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1998f86bb901SAdriana Kobylak if (filePath != nullptr) 1999f86bb901SAdriana Kobylak { 2000f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 2001e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 2002e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 2003f86bb901SAdriana Kobylak } 2004d1bde9e5SKrzysztof Grobelny }); 20057e860f15SJohn Edward Broadbent }); 2006336e96c6SChicago Duan 20077e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 200822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2009ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 20107e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 201145ca1b86SEd Tanous [&app](const crow::Request& req, 20127e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 201322d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 20143ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 201545ca1b86SEd Tanous { 201645ca1b86SEd Tanous return; 201745ca1b86SEd Tanous } 20187f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20197f3e84a1SEd Tanous { 20207f3e84a1SEd Tanous // Option currently returns no systems. TBD 20217f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20227f3e84a1SEd Tanous systemName); 20237f3e84a1SEd Tanous return; 20247f3e84a1SEd Tanous } 202522d268cbSEd Tanous if (systemName != "system") 202622d268cbSEd Tanous { 202722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 202822d268cbSEd Tanous systemName); 202922d268cbSEd Tanous return; 203022d268cbSEd Tanous } 203175710de2SXiaochao Ma std::optional<bool> resolved; 203275710de2SXiaochao Ma 203315ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 20347e860f15SJohn Edward Broadbent resolved)) 203575710de2SXiaochao Ma { 203675710de2SXiaochao Ma return; 203775710de2SXiaochao Ma } 203862598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 203975710de2SXiaochao Ma 20409ae226faSGeorge Liu sdbusplus::asio::setProperty( 20419ae226faSGeorge Liu *crow::connections::systemBus, "xyz.openbmc_project.Logging", 20429ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 20439ae226faSGeorge Liu "xyz.openbmc_project.Logging.Entry", "Resolved", *resolved, 20445e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 204575710de2SXiaochao Ma if (ec) 204675710de2SXiaochao Ma { 204762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 204875710de2SXiaochao Ma messages::internalError(asyncResp->res); 204975710de2SXiaochao Ma return; 205075710de2SXiaochao Ma } 20519ae226faSGeorge Liu }); 20527e860f15SJohn Edward Broadbent }); 205375710de2SXiaochao Ma 20547e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 205522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2056ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2057ed398213SEd Tanous 2058002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2059002d39b4SEd Tanous [&app](const crow::Request& req, 2060002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 206122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 20623ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2063336e96c6SChicago Duan { 206445ca1b86SEd Tanous return; 206545ca1b86SEd Tanous } 20667f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20677f3e84a1SEd Tanous { 20687f3e84a1SEd Tanous // Option currently returns no systems. TBD 20697f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20707f3e84a1SEd Tanous systemName); 20717f3e84a1SEd Tanous return; 20727f3e84a1SEd Tanous } 207322d268cbSEd Tanous if (systemName != "system") 207422d268cbSEd Tanous { 207522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 207622d268cbSEd Tanous systemName); 207722d268cbSEd Tanous return; 207822d268cbSEd Tanous } 207962598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 2080336e96c6SChicago Duan 20817e860f15SJohn Edward Broadbent std::string entryID = param; 2082336e96c6SChicago Duan 2083336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 2084336e96c6SChicago Duan 2085336e96c6SChicago Duan // Process response from Logging service. 2086*5a39f77aSPatrick Williams auto respHandler = [asyncResp, 2087*5a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 208862598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 2089336e96c6SChicago Duan if (ec) 2090336e96c6SChicago Duan { 20913de8d8baSGeorge Liu if (ec.value() == EBADR) 20923de8d8baSGeorge Liu { 209345ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 209445ca1b86SEd Tanous entryID); 20953de8d8baSGeorge Liu return; 20963de8d8baSGeorge Liu } 2097336e96c6SChicago Duan // TODO Handle for specific error code 209862598e31SEd Tanous BMCWEB_LOG_ERROR( 209962598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 210062598e31SEd Tanous ec); 2101336e96c6SChicago Duan asyncResp->res.result( 2102336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 2103336e96c6SChicago Duan return; 2104336e96c6SChicago Duan } 2105336e96c6SChicago Duan 2106336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 2107336e96c6SChicago Duan }; 2108336e96c6SChicago Duan 2109336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2110336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2111336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2112336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2113336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 21147e860f15SJohn Edward Broadbent }); 2115400fd1fbSAdriana Kobylak } 2116400fd1fbSAdriana Kobylak 2117b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2118b7028ebfSSpencer Ku 2119b7028ebfSSpencer Ku inline bool 2120b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2121b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2122b7028ebfSSpencer Ku { 2123b7028ebfSSpencer Ku std::error_code ec; 2124b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2125b7028ebfSSpencer Ku if (ec) 2126b7028ebfSSpencer Ku { 2127bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2128b7028ebfSSpencer Ku return false; 2129b7028ebfSSpencer Ku } 2130b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2131b7028ebfSSpencer Ku { 2132b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2133b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2134b7028ebfSSpencer Ku // path 213511ba3979SEd Tanous if (filename.starts_with("log")) 2136b7028ebfSSpencer Ku { 2137b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2138b7028ebfSSpencer Ku } 2139b7028ebfSSpencer Ku } 2140b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2141b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2142b7028ebfSSpencer Ku // descending order. 2143b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2144b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2145b7028ebfSSpencer Ku 2146b7028ebfSSpencer Ku return true; 2147b7028ebfSSpencer Ku } 2148b7028ebfSSpencer Ku 214902cad96eSEd Tanous inline bool getHostLoggerEntries( 215002cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 215102cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2152b7028ebfSSpencer Ku { 2153b7028ebfSSpencer Ku GzFileReader logFile; 2154b7028ebfSSpencer Ku 2155b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2156b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2157b7028ebfSSpencer Ku { 2158b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2159b7028ebfSSpencer Ku { 216062598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2161b7028ebfSSpencer Ku return false; 2162b7028ebfSSpencer Ku } 2163b7028ebfSSpencer Ku } 2164b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2165b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2166b7028ebfSSpencer Ku if (!lastMessage.empty()) 2167b7028ebfSSpencer Ku { 2168b7028ebfSSpencer Ku logCount++; 2169b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2170b7028ebfSSpencer Ku { 2171b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2172b7028ebfSSpencer Ku } 2173b7028ebfSSpencer Ku } 2174b7028ebfSSpencer Ku return true; 2175b7028ebfSSpencer Ku } 2176b7028ebfSSpencer Ku 2177b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2178b7028ebfSSpencer Ku const std::string& msg, 21796d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2180b7028ebfSSpencer Ku { 2181b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 21829c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2183ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2184ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2185ef4c65b7SEd Tanous logEntryID); 21866d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 21876d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 21886d6574c9SJason M. Bills logEntryJson["Message"] = msg; 21896d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 21906d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 21916d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2192b7028ebfSSpencer Ku } 2193b7028ebfSSpencer Ku 2194b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2195b7028ebfSSpencer Ku { 219622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2197b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 21981476687dSEd Tanous .methods(boost::beast::http::verb::get)( 21991476687dSEd Tanous [&app](const crow::Request& req, 220022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 220122d268cbSEd Tanous const std::string& systemName) { 22023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 220345ca1b86SEd Tanous { 220445ca1b86SEd Tanous return; 220545ca1b86SEd Tanous } 22067f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22077f3e84a1SEd Tanous { 22087f3e84a1SEd Tanous // Option currently returns no systems. TBD 22097f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22107f3e84a1SEd Tanous systemName); 22117f3e84a1SEd Tanous return; 22127f3e84a1SEd Tanous } 221322d268cbSEd Tanous if (systemName != "system") 221422d268cbSEd Tanous { 221522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 221622d268cbSEd Tanous systemName); 221722d268cbSEd Tanous return; 221822d268cbSEd Tanous } 2219b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2220b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2221b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2222b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2223b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2224b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2225b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 22261476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 22271476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2228b7028ebfSSpencer Ku }); 2229b7028ebfSSpencer Ku } 2230b7028ebfSSpencer Ku 2231b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2232b7028ebfSSpencer Ku { 2233b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 223422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2235b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2236002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2237002d39b4SEd Tanous [&app](const crow::Request& req, 223822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 223922d268cbSEd Tanous const std::string& systemName) { 2240c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2241c937d2bfSEd Tanous .canDelegateTop = true, 2242c937d2bfSEd Tanous .canDelegateSkip = true, 2243c937d2bfSEd Tanous }; 2244c937d2bfSEd Tanous query_param::Query delegatedQuery; 2245c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22463ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2247b7028ebfSSpencer Ku { 2248b7028ebfSSpencer Ku return; 2249b7028ebfSSpencer Ku } 22507f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22517f3e84a1SEd Tanous { 22527f3e84a1SEd Tanous // Option currently returns no systems. TBD 22537f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22547f3e84a1SEd Tanous systemName); 22557f3e84a1SEd Tanous return; 22567f3e84a1SEd Tanous } 225722d268cbSEd Tanous if (systemName != "system") 225822d268cbSEd Tanous { 225922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 226022d268cbSEd Tanous systemName); 226122d268cbSEd Tanous return; 226222d268cbSEd Tanous } 2263b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2264b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2265b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2266b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2267b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2268b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2269b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 22700fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2271b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2272b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2273b7028ebfSSpencer Ku 2274b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2275b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2276b7028ebfSSpencer Ku { 2277bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2278b7028ebfSSpencer Ku return; 2279b7028ebfSSpencer Ku } 22803648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 22813648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 22825143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2283b7028ebfSSpencer Ku size_t logCount = 0; 2284b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2285b7028ebfSSpencer Ku // control by skip and top. 2286b7028ebfSSpencer Ku std::vector<std::string> logEntries; 22873648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 22883648c8beSEd Tanous logCount)) 2289b7028ebfSSpencer Ku { 2290b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2291b7028ebfSSpencer Ku return; 2292b7028ebfSSpencer Ku } 2293b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2294b7028ebfSSpencer Ku // log count 229526f6976fSEd Tanous if (logEntries.empty()) 2296b7028ebfSSpencer Ku { 2297b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2298b7028ebfSSpencer Ku return; 2299b7028ebfSSpencer Ku } 230026f6976fSEd Tanous if (!logEntries.empty()) 2301b7028ebfSSpencer Ku { 2302b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2303b7028ebfSSpencer Ku { 23046d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23053648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 23063648c8beSEd Tanous hostLogEntry); 2307b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2308b7028ebfSSpencer Ku } 2309b7028ebfSSpencer Ku 2310b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 23113648c8beSEd Tanous if (skip + top < logCount) 2312b7028ebfSSpencer Ku { 2313b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 23140fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 23153648c8beSEd Tanous std::to_string(skip + top); 2316b7028ebfSSpencer Ku } 2317b7028ebfSSpencer Ku } 2318b7028ebfSSpencer Ku }); 2319b7028ebfSSpencer Ku } 2320b7028ebfSSpencer Ku 2321b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2322b7028ebfSSpencer Ku { 2323b7028ebfSSpencer Ku BMCWEB_ROUTE( 232422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2325b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2326b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 232745ca1b86SEd Tanous [&app](const crow::Request& req, 2328b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 232922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 23303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 233145ca1b86SEd Tanous { 233245ca1b86SEd Tanous return; 233345ca1b86SEd Tanous } 23347f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 23357f3e84a1SEd Tanous { 23367f3e84a1SEd Tanous // Option currently returns no systems. TBD 23377f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 23387f3e84a1SEd Tanous systemName); 23397f3e84a1SEd Tanous return; 23407f3e84a1SEd Tanous } 234122d268cbSEd Tanous if (systemName != "system") 234222d268cbSEd Tanous { 234322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 234422d268cbSEd Tanous systemName); 234522d268cbSEd Tanous return; 234622d268cbSEd Tanous } 2347b7028ebfSSpencer Ku const std::string& targetID = param; 2348b7028ebfSSpencer Ku 2349b7028ebfSSpencer Ku uint64_t idInt = 0; 2350ca45aa3cSEd Tanous 235184396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 235284396af9SPatrick Williams idInt); 23539db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 23549db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2355b7028ebfSSpencer Ku { 23569db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2357b7028ebfSSpencer Ku return; 2358b7028ebfSSpencer Ku } 2359b7028ebfSSpencer Ku 2360b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2361b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2362b7028ebfSSpencer Ku { 2363bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2364b7028ebfSSpencer Ku return; 2365b7028ebfSSpencer Ku } 2366b7028ebfSSpencer Ku 2367b7028ebfSSpencer Ku size_t logCount = 0; 23683648c8beSEd Tanous size_t top = 1; 2369b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2370b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2371b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2372b7028ebfSSpencer Ku // get that entry 2373002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2374002d39b4SEd Tanous logCount)) 2375b7028ebfSSpencer Ku { 2376b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2377b7028ebfSSpencer Ku return; 2378b7028ebfSSpencer Ku } 2379b7028ebfSSpencer Ku 2380b7028ebfSSpencer Ku if (!logEntries.empty()) 2381b7028ebfSSpencer Ku { 23826d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23836d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 23846d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2385b7028ebfSSpencer Ku return; 2386b7028ebfSSpencer Ku } 2387b7028ebfSSpencer Ku 2388b7028ebfSSpencer Ku // Requested ID was not found 23899db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2390b7028ebfSSpencer Ku }); 2391b7028ebfSSpencer Ku } 2392b7028ebfSSpencer Ku 2393dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2394fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2395fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 23961da66f75SEd Tanous { 23973ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 239845ca1b86SEd Tanous { 239945ca1b86SEd Tanous return; 240045ca1b86SEd Tanous } 24017e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24027e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2403e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 24041da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2405e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2406e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2407002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2408e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 24091da66f75SEd Tanous "Collection of LogServices for this Manager"; 2410002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2411c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2412fdd26906SClaire Weinan 2413c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2414613dabeaSEd Tanous nlohmann::json::object_t journal; 2415613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2416b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2417c4bf6374SJason M. Bills #endif 2418fdd26906SClaire Weinan 2419fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2420fdd26906SClaire Weinan 2421fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 242215912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24237a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 24247a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 24257a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2426fdd26906SClaire Weinan [asyncResp]( 24277a1dbc48SGeorge Liu const boost::system::error_code& ec, 2428fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2429fdd26906SClaire Weinan if (ec) 2430fdd26906SClaire Weinan { 243162598e31SEd Tanous BMCWEB_LOG_ERROR( 243262598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 243362598e31SEd Tanous ec); 2434fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2435fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2436fdd26906SClaire Weinan return; 2437fdd26906SClaire Weinan } 2438fdd26906SClaire Weinan 2439fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2440fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2441fdd26906SClaire Weinan 2442fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2443fdd26906SClaire Weinan { 2444fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2445fdd26906SClaire Weinan { 2446613dabeaSEd Tanous nlohmann::json::object_t member; 2447613dabeaSEd Tanous member["@odata.id"] = 2448613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2449b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2450fdd26906SClaire Weinan } 2451fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2452fdd26906SClaire Weinan { 2453613dabeaSEd Tanous nlohmann::json::object_t member; 2454613dabeaSEd Tanous member["@odata.id"] = 2455613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2456b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2457fdd26906SClaire Weinan } 2458fdd26906SClaire Weinan } 2459fdd26906SClaire Weinan 2460e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2461fdd26906SClaire Weinan logServiceArrayLocal.size(); 24627a1dbc48SGeorge Liu }); 2463fdd26906SClaire Weinan #endif 2464fdd26906SClaire Weinan } 2465fdd26906SClaire Weinan 2466fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2467fdd26906SClaire Weinan { 2468fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2469fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2470fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2471dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2472e1f26343SJason M. Bills } 2473e1f26343SJason M. Bills 24747e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2475e1f26343SJason M. Bills { 24767e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2477ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 24787e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 247945ca1b86SEd Tanous [&app](const crow::Request& req, 248045ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 24813ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 24827e860f15SJohn Edward Broadbent { 248345ca1b86SEd Tanous return; 248445ca1b86SEd Tanous } 2485e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2486b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 24870f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24880f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2489002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2490002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2491ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2492e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 24937c8c4058STejas Patil 24947c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 24952b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2496002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 24977c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 24987c8c4058STejas Patil redfishDateTimeOffset.second; 24997c8c4058STejas Patil 25001476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 25011476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 25027e860f15SJohn Edward Broadbent }); 2503e1f26343SJason M. Bills } 2504e1f26343SJason M. Bills 25053a48b3a2SJason M. Bills static int 25063a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2507e1f26343SJason M. Bills sd_journal* journal, 25083a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2509e1f26343SJason M. Bills { 2510e1f26343SJason M. Bills // Get the Log Entry contents 2511e1f26343SJason M. Bills int ret = 0; 2512e1f26343SJason M. Bills 2513a8fe54f0SJason M. Bills std::string message; 2514a8fe54f0SJason M. Bills std::string_view syslogID; 2515a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2516a8fe54f0SJason M. Bills if (ret < 0) 2517a8fe54f0SJason M. Bills { 2518bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 251962598e31SEd Tanous strerror(-ret)); 2520a8fe54f0SJason M. Bills } 2521a8fe54f0SJason M. Bills if (!syslogID.empty()) 2522a8fe54f0SJason M. Bills { 2523a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2524a8fe54f0SJason M. Bills } 2525a8fe54f0SJason M. Bills 252639e77504SEd Tanous std::string_view msg; 252716428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2528e1f26343SJason M. Bills if (ret < 0) 2529e1f26343SJason M. Bills { 253062598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2531e1f26343SJason M. Bills return 1; 2532e1f26343SJason M. Bills } 2533a8fe54f0SJason M. Bills message += std::string(msg); 2534e1f26343SJason M. Bills 2535e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2536271584abSEd Tanous long int severity = 8; // Default to an invalid priority 253716428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2538e1f26343SJason M. Bills if (ret < 0) 2539e1f26343SJason M. Bills { 2540bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2541e1f26343SJason M. Bills } 2542e1f26343SJason M. Bills 2543e1f26343SJason M. Bills // Get the Created time from the timestamp 254416428a1aSJason M. Bills std::string entryTimeStr; 254516428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2546e1f26343SJason M. Bills { 254716428a1aSJason M. Bills return 1; 2548e1f26343SJason M. Bills } 2549e1f26343SJason M. Bills 2550e1f26343SJason M. Bills // Fill in the log entry with the gathered data 25519c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2552ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2553ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2554eddfc437SWilly Tu bmcJournalLogEntryID); 255584afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 255684afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 255784afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 255884afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 255984afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2560738c1e61SPatrick Williams : severity <= 4 ? "Warning" 256184afc48bSJason M. Bills : "OK"; 256284afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 256384afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2564e1f26343SJason M. Bills return 0; 2565e1f26343SJason M. Bills } 2566e1f26343SJason M. Bills 25677e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2568e1f26343SJason M. Bills { 25697e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2570ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2571002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2572002d39b4SEd Tanous [&app](const crow::Request& req, 2573002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2574c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2575c937d2bfSEd Tanous .canDelegateTop = true, 2576c937d2bfSEd Tanous .canDelegateSkip = true, 2577c937d2bfSEd Tanous }; 2578c937d2bfSEd Tanous query_param::Query delegatedQuery; 2579c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 25803ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2581193ad2faSJason M. Bills { 2582193ad2faSJason M. Bills return; 2583193ad2faSJason M. Bills } 25843648c8beSEd Tanous 25853648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 25865143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 25873648c8beSEd Tanous 25887e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 25897e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2590e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2591e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 25920f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 25930f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2594e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2595e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2596e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 25970fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2598e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2599e1f26343SJason M. Bills 26007e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 26017e860f15SJohn Edward Broadbent // unique ID for each entry 2602e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2603e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2604e1f26343SJason M. Bills if (ret < 0) 2605e1f26343SJason M. Bills { 260662598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2607f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2608e1f26343SJason M. Bills return; 2609e1f26343SJason M. Bills } 26100fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 26110fda0f12SGeorge Liu journalTmp, sd_journal_close); 2612e1f26343SJason M. Bills journalTmp = nullptr; 2613b01bf299SEd Tanous uint64_t entryCount = 0; 2614e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2615e85d6b16SJason M. Bills bool firstEntry = true; 2616e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2617e1f26343SJason M. Bills { 2618193ad2faSJason M. Bills entryCount++; 26197e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 26207e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 26213648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2622193ad2faSJason M. Bills { 2623193ad2faSJason M. Bills continue; 2624193ad2faSJason M. Bills } 2625193ad2faSJason M. Bills 262616428a1aSJason M. Bills std::string idStr; 2627e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2628e1f26343SJason M. Bills { 2629e1f26343SJason M. Bills continue; 2630e1f26343SJason M. Bills } 2631e85d6b16SJason M. Bills firstEntry = false; 2632e85d6b16SJason M. Bills 26333a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2634c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2635c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2636e1f26343SJason M. Bills { 2637f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2638e1f26343SJason M. Bills return; 2639e1f26343SJason M. Bills } 2640b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2641e1f26343SJason M. Bills } 2642193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 26433648c8beSEd Tanous if (skip + top < entryCount) 2644193ad2faSJason M. Bills { 2645193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 26460fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 26473648c8beSEd Tanous std::to_string(skip + top); 2648193ad2faSJason M. Bills } 26497e860f15SJohn Edward Broadbent }); 2650e1f26343SJason M. Bills } 2651e1f26343SJason M. Bills 26527e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2653e1f26343SJason M. Bills { 26547e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26557e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2656ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 26577e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 265845ca1b86SEd Tanous [&app](const crow::Request& req, 26597e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26607e860f15SJohn Edward Broadbent const std::string& entryID) { 26613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 266245ca1b86SEd Tanous { 266345ca1b86SEd Tanous return; 266445ca1b86SEd Tanous } 2665e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2666e1f26343SJason M. Bills uint64_t ts = 0; 2667271584abSEd Tanous uint64_t index = 0; 26688d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2669e1f26343SJason M. Bills { 267016428a1aSJason M. Bills return; 2671e1f26343SJason M. Bills } 2672e1f26343SJason M. Bills 2673e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2674e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2675e1f26343SJason M. Bills if (ret < 0) 2676e1f26343SJason M. Bills { 267762598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2678f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2679e1f26343SJason M. Bills return; 2680e1f26343SJason M. Bills } 2681002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2682002d39b4SEd Tanous journalTmp, sd_journal_close); 2683e1f26343SJason M. Bills journalTmp = nullptr; 26847e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 26857e860f15SJohn Edward Broadbent // index tracking the unique ID 2686af07e3f5SJason M. Bills std::string idStr; 2687af07e3f5SJason M. Bills bool firstEntry = true; 2688e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 26892056b6d1SManojkiran Eda if (ret < 0) 26902056b6d1SManojkiran Eda { 269162598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 269262598e31SEd Tanous strerror(-ret)); 26932056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 26942056b6d1SManojkiran Eda return; 26952056b6d1SManojkiran Eda } 2696271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2697e1f26343SJason M. Bills { 2698e1f26343SJason M. Bills sd_journal_next(journal.get()); 2699af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2700af07e3f5SJason M. Bills { 2701af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2702af07e3f5SJason M. Bills return; 2703af07e3f5SJason M. Bills } 2704af07e3f5SJason M. Bills firstEntry = false; 2705af07e3f5SJason M. Bills } 2706c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2707af07e3f5SJason M. Bills if (idStr != entryID) 2708c4bf6374SJason M. Bills { 27099db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2710c4bf6374SJason M. Bills return; 2711c4bf6374SJason M. Bills } 2712c4bf6374SJason M. Bills 27133a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2714c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 27153a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2716e1f26343SJason M. Bills { 2717f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2718e1f26343SJason M. Bills return; 2719e1f26343SJason M. Bills } 2720d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 27217e860f15SJohn Edward Broadbent }); 2722c9bb6861Sraviteja-b } 2723c9bb6861Sraviteja-b 2724fdd26906SClaire Weinan inline void 2725fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2726fdd26906SClaire Weinan const std::string& dumpType) 2727c9bb6861Sraviteja-b { 2728fdd26906SClaire Weinan std::string dumpPath; 2729fdd26906SClaire Weinan std::string overWritePolicy; 2730fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2731fdd26906SClaire Weinan 2732fdd26906SClaire Weinan if (dumpType == "BMC") 273345ca1b86SEd Tanous { 2734fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2735fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2736fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2737fdd26906SClaire Weinan } 2738fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2739fdd26906SClaire Weinan { 2740fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2741fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2742fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2743fdd26906SClaire Weinan } 2744fdd26906SClaire Weinan else if (dumpType == "System") 2745fdd26906SClaire Weinan { 2746fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2747fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2748fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2749fdd26906SClaire Weinan } 2750fdd26906SClaire Weinan else 2751fdd26906SClaire Weinan { 275262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 275362598e31SEd Tanous dumpType); 2754fdd26906SClaire Weinan messages::internalError(asyncResp->res); 275545ca1b86SEd Tanous return; 275645ca1b86SEd Tanous } 2757fdd26906SClaire Weinan 2758fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2759fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2760c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2761fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2762fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2763fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 27647c8c4058STejas Patil 27657c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 27662b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 27670fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 27687c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 27697c8c4058STejas Patil redfishDateTimeOffset.second; 27707c8c4058STejas Patil 2771fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2772fdd26906SClaire Weinan 2773fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2774fdd26906SClaire Weinan { 2775002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 27761476687dSEd Tanous ["target"] = 2777fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2778fdd26906SClaire Weinan } 27790d946211SClaire Weinan 27800d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 27810d946211SClaire Weinan dbus::utility::getSubTreePaths( 27820d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 27830d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 27840d946211SClaire Weinan const boost::system::error_code& ec, 27850d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 27860d946211SClaire Weinan if (ec) 27870d946211SClaire Weinan { 278862598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 27890d946211SClaire Weinan // Assume that getting an error simply means there are no dump 27900d946211SClaire Weinan // LogServices. Return without adding any error response. 27910d946211SClaire Weinan return; 27920d946211SClaire Weinan } 27930d946211SClaire Weinan 27940d946211SClaire Weinan const std::string dbusDumpPath = 27950d946211SClaire Weinan "/xyz/openbmc_project/dump/" + 27960d946211SClaire Weinan boost::algorithm::to_lower_copy(dumpType); 27970d946211SClaire Weinan 27980d946211SClaire Weinan for (const std::string& path : subTreePaths) 27990d946211SClaire Weinan { 28000d946211SClaire Weinan if (path == dbusDumpPath) 28010d946211SClaire Weinan { 28020d946211SClaire Weinan asyncResp->res 28030d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 28040d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 28050d946211SClaire Weinan break; 28060d946211SClaire Weinan } 28070d946211SClaire Weinan } 28080d946211SClaire Weinan }); 2809c9bb6861Sraviteja-b } 2810c9bb6861Sraviteja-b 2811fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2812fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2813fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 28147e860f15SJohn Edward Broadbent { 28153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 281645ca1b86SEd Tanous { 281745ca1b86SEd Tanous return; 281845ca1b86SEd Tanous } 2819fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2820fdd26906SClaire Weinan } 2821c9bb6861Sraviteja-b 282222d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 282322d268cbSEd Tanous crow::App& app, const crow::Request& req, 282422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 282522d268cbSEd Tanous const std::string& chassisId) 282622d268cbSEd Tanous { 282722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 282822d268cbSEd Tanous { 282922d268cbSEd Tanous return; 283022d268cbSEd Tanous } 283122d268cbSEd Tanous if (chassisId != "system") 283222d268cbSEd Tanous { 283322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 283422d268cbSEd Tanous return; 283522d268cbSEd Tanous } 283622d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 283722d268cbSEd Tanous } 283822d268cbSEd Tanous 2839fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2840fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2841fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2842fdd26906SClaire Weinan { 2843fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2844fdd26906SClaire Weinan { 2845fdd26906SClaire Weinan return; 2846fdd26906SClaire Weinan } 2847fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2848fdd26906SClaire Weinan } 2849fdd26906SClaire Weinan 285022d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 285122d268cbSEd Tanous crow::App& app, const crow::Request& req, 285222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 285322d268cbSEd Tanous const std::string& chassisId) 285422d268cbSEd Tanous { 285522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 285622d268cbSEd Tanous { 285722d268cbSEd Tanous return; 285822d268cbSEd Tanous } 285922d268cbSEd Tanous if (chassisId != "system") 286022d268cbSEd Tanous { 286122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 286222d268cbSEd Tanous return; 286322d268cbSEd Tanous } 286422d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 286522d268cbSEd Tanous } 286622d268cbSEd Tanous 2867fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2868fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2869fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2870fdd26906SClaire Weinan const std::string& dumpId) 2871fdd26906SClaire Weinan { 2872fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2873fdd26906SClaire Weinan { 2874fdd26906SClaire Weinan return; 2875fdd26906SClaire Weinan } 2876fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2877fdd26906SClaire Weinan } 2878168d1b1aSCarson Labrado 287922d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 288022d268cbSEd Tanous crow::App& app, const crow::Request& req, 288122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 288222d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 288322d268cbSEd Tanous { 288422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 288522d268cbSEd Tanous { 288622d268cbSEd Tanous return; 288722d268cbSEd Tanous } 288822d268cbSEd Tanous if (chassisId != "system") 288922d268cbSEd Tanous { 289022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 289122d268cbSEd Tanous return; 289222d268cbSEd Tanous } 289322d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 289422d268cbSEd Tanous } 2895fdd26906SClaire Weinan 2896fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2897fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2898fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2899fdd26906SClaire Weinan const std::string& dumpId) 2900fdd26906SClaire Weinan { 2901fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2902fdd26906SClaire Weinan { 2903fdd26906SClaire Weinan return; 2904fdd26906SClaire Weinan } 2905fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2906fdd26906SClaire Weinan } 2907fdd26906SClaire Weinan 290822d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 290922d268cbSEd Tanous crow::App& app, const crow::Request& req, 291022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 291122d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 291222d268cbSEd Tanous { 291322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 291422d268cbSEd Tanous { 291522d268cbSEd Tanous return; 291622d268cbSEd Tanous } 291722d268cbSEd Tanous if (chassisId != "system") 291822d268cbSEd Tanous { 291922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 292022d268cbSEd Tanous return; 292122d268cbSEd Tanous } 292222d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 292322d268cbSEd Tanous } 292422d268cbSEd Tanous 2925168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2926168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2927168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2928168d1b1aSCarson Labrado const std::string& dumpId) 2929168d1b1aSCarson Labrado { 2930168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2931168d1b1aSCarson Labrado { 2932168d1b1aSCarson Labrado return; 2933168d1b1aSCarson Labrado } 2934168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2935168d1b1aSCarson Labrado } 2936168d1b1aSCarson Labrado 2937168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2938168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2939168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2940168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2941168d1b1aSCarson Labrado { 2942168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2943168d1b1aSCarson Labrado { 2944168d1b1aSCarson Labrado return; 2945168d1b1aSCarson Labrado } 2946168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2947168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2948168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2949168d1b1aSCarson Labrado { 2950168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2951168d1b1aSCarson Labrado return; 2952168d1b1aSCarson Labrado } 2953168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2954168d1b1aSCarson Labrado } 2955168d1b1aSCarson Labrado 2956fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2957fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2958fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2959fdd26906SClaire Weinan { 2960fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2961fdd26906SClaire Weinan { 2962fdd26906SClaire Weinan return; 2963fdd26906SClaire Weinan } 2964fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2965fdd26906SClaire Weinan } 2966fdd26906SClaire Weinan 296722d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 296822d268cbSEd Tanous crow::App& app, const crow::Request& req, 296922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29707f3e84a1SEd Tanous const std::string& systemName) 297122d268cbSEd Tanous { 297222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 297322d268cbSEd Tanous { 297422d268cbSEd Tanous return; 297522d268cbSEd Tanous } 29767f3e84a1SEd Tanous 29777f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 297822d268cbSEd Tanous { 29797f3e84a1SEd Tanous // Option currently returns no systems. TBD 29807f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29817f3e84a1SEd Tanous systemName); 29827f3e84a1SEd Tanous return; 29837f3e84a1SEd Tanous } 29847f3e84a1SEd Tanous if (systemName != "system") 29857f3e84a1SEd Tanous { 29867f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29877f3e84a1SEd Tanous systemName); 298822d268cbSEd Tanous return; 298922d268cbSEd Tanous } 299022d268cbSEd Tanous createDump(asyncResp, req, "System"); 299122d268cbSEd Tanous } 299222d268cbSEd Tanous 2993fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2994fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2995fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2996fdd26906SClaire Weinan { 2997fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2998fdd26906SClaire Weinan { 2999fdd26906SClaire Weinan return; 3000fdd26906SClaire Weinan } 3001fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 3002fdd26906SClaire Weinan } 3003fdd26906SClaire Weinan 300422d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 300522d268cbSEd Tanous crow::App& app, const crow::Request& req, 300622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30077f3e84a1SEd Tanous const std::string& systemName) 300822d268cbSEd Tanous { 300922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 301022d268cbSEd Tanous { 301122d268cbSEd Tanous return; 301222d268cbSEd 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 clearDump(asyncResp, "System"); 302722d268cbSEd Tanous } 302822d268cbSEd Tanous 3029fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 3030fdd26906SClaire Weinan { 3031fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 3032fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3033fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3034fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 3035fdd26906SClaire Weinan } 3036fdd26906SClaire Weinan 3037fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 3038fdd26906SClaire Weinan { 3039fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 3040fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3041fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3042fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 3043c9bb6861Sraviteja-b } 3044c9bb6861Sraviteja-b 30457e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 3046c9bb6861Sraviteja-b { 30477e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30487e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3049ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 3050fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3051fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 3052fdd26906SClaire Weinan 30537e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30547e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3055ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 3056fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3057fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 3058c9bb6861Sraviteja-b } 3059c9bb6861Sraviteja-b 3060168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 3061168d1b1aSCarson Labrado { 3062168d1b1aSCarson Labrado BMCWEB_ROUTE( 3063168d1b1aSCarson Labrado app, 3064168d1b1aSCarson Labrado "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment") 3065168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3066168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3067168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 3068168d1b1aSCarson Labrado } 3069168d1b1aSCarson Labrado 30707e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 3071c9bb6861Sraviteja-b { 30720fda0f12SGeorge Liu BMCWEB_ROUTE( 30730fda0f12SGeorge Liu app, 30740fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3075ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 30767e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 3077fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 3078fdd26906SClaire Weinan std::ref(app), "BMC")); 3079a43be80fSAsmitha Karunanithi } 3080a43be80fSAsmitha Karunanithi 30817e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 308280319af1SAsmitha Karunanithi { 30830fda0f12SGeorge Liu BMCWEB_ROUTE( 30840fda0f12SGeorge Liu app, 30850fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 3086ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 3087fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3088fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 308945ca1b86SEd Tanous } 3090fdd26906SClaire Weinan 3091168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 3092168d1b1aSCarson Labrado { 3093168d1b1aSCarson Labrado BMCWEB_ROUTE( 3094168d1b1aSCarson Labrado app, 3095168d1b1aSCarson Labrado "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 3096168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3097168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3098168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 3099168d1b1aSCarson Labrado } 3100168d1b1aSCarson Labrado 3101fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3102fdd26906SClaire Weinan { 3103fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 3104fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3105fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3106fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3107fdd26906SClaire Weinan } 3108fdd26906SClaire Weinan 3109fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3110fdd26906SClaire Weinan { 3111fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 3112fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3113fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3114fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3115fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3116fdd26906SClaire Weinan } 3117fdd26906SClaire Weinan 3118fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3119fdd26906SClaire Weinan { 3120fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3121fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3122fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3123fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3124fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3125fdd26906SClaire Weinan 3126fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3127fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3128fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3129fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3130fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3131fdd26906SClaire Weinan } 3132fdd26906SClaire Weinan 3133fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3134fdd26906SClaire Weinan { 3135fdd26906SClaire Weinan BMCWEB_ROUTE( 3136fdd26906SClaire Weinan app, 3137fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 3138fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3139fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3140fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 31415cb1dd27SAsmitha Karunanithi } 31425cb1dd27SAsmitha Karunanithi 31437e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 31445cb1dd27SAsmitha Karunanithi { 314522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3146ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 31476ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 314822d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 31495cb1dd27SAsmitha Karunanithi } 31505cb1dd27SAsmitha Karunanithi 31517e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 31527e860f15SJohn Edward Broadbent { 315322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3154ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 315522d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 315622d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 315722d268cbSEd Tanous std::ref(app))); 31585cb1dd27SAsmitha Karunanithi } 31595cb1dd27SAsmitha Karunanithi 31607e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 31615cb1dd27SAsmitha Karunanithi { 31627e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 316322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3164ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 31656ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 316622d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 31678d1b46d7Szhanghch05 31687e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 316922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3170ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 31716ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 317222d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 31735cb1dd27SAsmitha Karunanithi } 3174c9bb6861Sraviteja-b 31757e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3176c9bb6861Sraviteja-b { 31770fda0f12SGeorge Liu BMCWEB_ROUTE( 31780fda0f12SGeorge Liu app, 317922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3180ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 318122d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 318222d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 318322d268cbSEd Tanous std::ref(app))); 3184a43be80fSAsmitha Karunanithi } 3185a43be80fSAsmitha Karunanithi 31867e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3187a43be80fSAsmitha Karunanithi { 31880fda0f12SGeorge Liu BMCWEB_ROUTE( 31890fda0f12SGeorge Liu app, 319022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3191ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 31926ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 319322d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3194013487e5Sraviteja-b } 3195013487e5Sraviteja-b 31967e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 31971da66f75SEd Tanous { 31983946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31993946028dSAppaRao Puli // method for security reasons. 32001da66f75SEd Tanous /** 32011da66f75SEd Tanous * Functions triggers appropriate requests on DBus 32021da66f75SEd Tanous */ 320322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3204ed398213SEd Tanous // This is incorrect, should be: 3205ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3206432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3207002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3208002d39b4SEd Tanous [&app](const crow::Request& req, 320922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 321022d268cbSEd Tanous const std::string& systemName) { 32113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 321245ca1b86SEd Tanous { 321345ca1b86SEd Tanous return; 321445ca1b86SEd Tanous } 32157f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32167f3e84a1SEd Tanous { 32177f3e84a1SEd Tanous // Option currently returns no systems. TBD 32187f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32197f3e84a1SEd Tanous systemName); 32207f3e84a1SEd Tanous return; 32217f3e84a1SEd Tanous } 322222d268cbSEd Tanous if (systemName != "system") 322322d268cbSEd Tanous { 322422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 322522d268cbSEd Tanous systemName); 322622d268cbSEd Tanous return; 322722d268cbSEd Tanous } 322822d268cbSEd Tanous 32297e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 32307e860f15SJohn Edward Broadbent // SubRoute 32310f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3232424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3233e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32348e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 32354f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 32364f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 323715b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3238e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3239e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 32407c8c4058STejas Patil 32417c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 32422b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 32437c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 32447c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 32457c8c4058STejas Patil redfishDateTimeOffset.second; 32467c8c4058STejas Patil 32471476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3248ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3249002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 32501476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3251002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 32521476687dSEd Tanous ["target"] = 32531476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 32547e860f15SJohn Edward Broadbent }); 32551da66f75SEd Tanous } 32561da66f75SEd Tanous 32577e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 32585b61b5e8SJason M. Bills { 32590fda0f12SGeorge Liu BMCWEB_ROUTE( 32600fda0f12SGeorge Liu app, 326122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3262ed398213SEd Tanous // This is incorrect, should be: 3263ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3264432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 326645ca1b86SEd Tanous [&app](const crow::Request& req, 326722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 326822d268cbSEd Tanous const std::string& systemName) { 32693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 327045ca1b86SEd Tanous { 327145ca1b86SEd Tanous return; 327245ca1b86SEd Tanous } 32737f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32747f3e84a1SEd Tanous { 32757f3e84a1SEd Tanous // Option currently returns no systems. TBD 32767f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32777f3e84a1SEd Tanous systemName); 32787f3e84a1SEd Tanous return; 32797f3e84a1SEd Tanous } 328022d268cbSEd Tanous if (systemName != "system") 328122d268cbSEd Tanous { 328222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 328322d268cbSEd Tanous systemName); 328422d268cbSEd Tanous return; 328522d268cbSEd Tanous } 32865b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 32875e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3288cb13a392SEd Tanous const std::string&) { 32895b61b5e8SJason M. Bills if (ec) 32905b61b5e8SJason M. Bills { 32915b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 32925b61b5e8SJason M. Bills return; 32935b61b5e8SJason M. Bills } 32945b61b5e8SJason M. Bills messages::success(asyncResp->res); 32955b61b5e8SJason M. Bills }, 3296002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 32977e860f15SJohn Edward Broadbent }); 32985b61b5e8SJason M. Bills } 32995b61b5e8SJason M. Bills 33008d1b46d7Szhanghch05 static void 33018d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 33028d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3303e855dd28SJason M. Bills { 3304043a0536SJohnathan Mantey auto getStoredLogCallback = 3305b9d36b47SEd Tanous [asyncResp, logID, 33065e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3307b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3308e855dd28SJason M. Bills if (ec) 3309e855dd28SJason M. Bills { 331062598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 33111ddcf01aSJason M. Bills if (ec.value() == 33121ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 33131ddcf01aSJason M. Bills { 3314002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33151ddcf01aSJason M. Bills } 33161ddcf01aSJason M. Bills else 33171ddcf01aSJason M. Bills { 3318e855dd28SJason M. Bills messages::internalError(asyncResp->res); 33191ddcf01aSJason M. Bills } 3320e855dd28SJason M. Bills return; 3321e855dd28SJason M. Bills } 3322043a0536SJohnathan Mantey 3323043a0536SJohnathan Mantey std::string timestamp{}; 3324043a0536SJohnathan Mantey std::string filename{}; 3325043a0536SJohnathan Mantey std::string logfile{}; 33262c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3327043a0536SJohnathan Mantey 3328043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3329e855dd28SJason M. Bills { 33309db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3331e855dd28SJason M. Bills return; 3332e855dd28SJason M. Bills } 3333e855dd28SJason M. Bills 3334043a0536SJohnathan Mantey std::string crashdumpURI = 3335e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3336043a0536SJohnathan Mantey logID + "/" + filename; 333784afc48bSJason M. Bills nlohmann::json::object_t logEntry; 33389c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3339ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3340ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3341ef4c65b7SEd Tanous logID); 334284afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 334384afc48bSJason M. Bills logEntry["Id"] = logID; 334484afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 334584afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 334684afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 334784afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 334884afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 33492b20ef6eSJason M. Bills 33502b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 33512b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 33522b20ef6eSJason M. Bills // directly 33532b20ef6eSJason M. Bills if (logEntryJson.is_array()) 33542b20ef6eSJason M. Bills { 33552b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 33562b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 33572b20ef6eSJason M. Bills logEntryJson.size(); 33582b20ef6eSJason M. Bills } 33592b20ef6eSJason M. Bills else 33602b20ef6eSJason M. Bills { 3361d405bb51SJason M. Bills logEntryJson.update(logEntry); 33622b20ef6eSJason M. Bills } 3363e855dd28SJason M. Bills }; 3364d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3365d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3366d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3367d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3368e855dd28SJason M. Bills } 3369e855dd28SJason M. Bills 33707e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 33711da66f75SEd Tanous { 33723946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33733946028dSAppaRao Puli // method for security reasons. 33741da66f75SEd Tanous /** 33751da66f75SEd Tanous * Functions triggers appropriate requests on DBus 33761da66f75SEd Tanous */ 33777e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 337822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3379ed398213SEd Tanous // This is incorrect, should be. 3380ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3381432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3382002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3383002d39b4SEd Tanous [&app](const crow::Request& req, 338422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 338522d268cbSEd Tanous const std::string& systemName) { 33863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 338745ca1b86SEd Tanous { 338845ca1b86SEd Tanous return; 338945ca1b86SEd Tanous } 33907f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 33917f3e84a1SEd Tanous { 33927f3e84a1SEd Tanous // Option currently returns no systems. TBD 33937f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33947f3e84a1SEd Tanous systemName); 33957f3e84a1SEd Tanous return; 33967f3e84a1SEd Tanous } 339722d268cbSEd Tanous if (systemName != "system") 339822d268cbSEd Tanous { 339922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 340022d268cbSEd Tanous systemName); 340122d268cbSEd Tanous return; 340222d268cbSEd Tanous } 340322d268cbSEd Tanous 34047a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 34057a1dbc48SGeorge Liu crashdumpInterface}; 34067a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 34077a1dbc48SGeorge Liu "/", 0, interfaces, 34087a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 34092b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 34101da66f75SEd Tanous if (ec) 34111da66f75SEd Tanous { 34121da66f75SEd Tanous if (ec.value() != 34131da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 34141da66f75SEd Tanous { 341562598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 341662598e31SEd Tanous ec.message()); 3417f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34181da66f75SEd Tanous return; 34191da66f75SEd Tanous } 34201da66f75SEd Tanous } 3421e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 34221da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 34230f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3424424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3425002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3426e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3427424c4176SJason M. Bills "Collection of Crashdump Entries"; 3428002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3429a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 34302b20ef6eSJason M. Bills 34312b20ef6eSJason M. Bills for (const std::string& path : resp) 34321da66f75SEd Tanous { 34332b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3434e855dd28SJason M. Bills // Get the log ID 34352b20ef6eSJason M. Bills std::string logID = objPath.filename(); 34362b20ef6eSJason M. Bills if (logID.empty()) 34371da66f75SEd Tanous { 3438e855dd28SJason M. Bills continue; 34391da66f75SEd Tanous } 3440e855dd28SJason M. Bills // Add the log entry to the array 34412b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 34422b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 34431da66f75SEd Tanous } 34447a1dbc48SGeorge Liu }); 34457e860f15SJohn Edward Broadbent }); 34461da66f75SEd Tanous } 34471da66f75SEd Tanous 34487e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 34491da66f75SEd Tanous { 34503946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34513946028dSAppaRao Puli // method for security reasons. 34521da66f75SEd Tanous 34537e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 345422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3455ed398213SEd Tanous // this is incorrect, should be 3456ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3457432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 34587e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 345945ca1b86SEd Tanous [&app](const crow::Request& req, 34607e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 346122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 34623ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 346345ca1b86SEd Tanous { 346445ca1b86SEd Tanous return; 346545ca1b86SEd Tanous } 34667f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34677f3e84a1SEd Tanous { 34687f3e84a1SEd Tanous // Option currently returns no systems. TBD 34697f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34707f3e84a1SEd Tanous systemName); 34717f3e84a1SEd Tanous return; 34727f3e84a1SEd Tanous } 347322d268cbSEd Tanous if (systemName != "system") 347422d268cbSEd Tanous { 347522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 347622d268cbSEd Tanous systemName); 347722d268cbSEd Tanous return; 347822d268cbSEd Tanous } 34797e860f15SJohn Edward Broadbent const std::string& logID = param; 3480e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 34817e860f15SJohn Edward Broadbent }); 3482e855dd28SJason M. Bills } 3483e855dd28SJason M. Bills 34847e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3485e855dd28SJason M. Bills { 34863946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34873946028dSAppaRao Puli // method for security reasons. 34887e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 34897e860f15SJohn Edward Broadbent app, 349022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3491ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 34927e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3493a4ce114aSNan Zhou [](const crow::Request& req, 34947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 349522d268cbSEd Tanous const std::string& systemName, const std::string& logID, 349622d268cbSEd Tanous const std::string& fileName) { 34972a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 34982a9beeedSShounak Mitra // Redfish resource. 349922d268cbSEd Tanous 35007f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35017f3e84a1SEd Tanous { 35027f3e84a1SEd Tanous // Option currently returns no systems. TBD 35037f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35047f3e84a1SEd Tanous systemName); 35057f3e84a1SEd Tanous return; 35067f3e84a1SEd Tanous } 350722d268cbSEd Tanous if (systemName != "system") 350822d268cbSEd Tanous { 350922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 351022d268cbSEd Tanous systemName); 351122d268cbSEd Tanous return; 351222d268cbSEd Tanous } 351322d268cbSEd Tanous 3514043a0536SJohnathan Mantey auto getStoredLogCallback = 351539662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 35165e7e2dc5SEd Tanous const boost::system::error_code& ec, 3517002d39b4SEd Tanous const std::vector< 3518002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 35197e860f15SJohn Edward Broadbent resp) { 35201da66f75SEd Tanous if (ec) 35211da66f75SEd Tanous { 352262598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3523f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35241da66f75SEd Tanous return; 35251da66f75SEd Tanous } 3526e855dd28SJason M. Bills 3527043a0536SJohnathan Mantey std::string dbusFilename{}; 3528043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3529043a0536SJohnathan Mantey std::string dbusFilepath{}; 3530043a0536SJohnathan Mantey 3531002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3532002d39b4SEd Tanous dbusFilepath); 3533043a0536SJohnathan Mantey 3534043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3535043a0536SJohnathan Mantey dbusFilepath.empty()) 35361da66f75SEd Tanous { 35379db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 35381da66f75SEd Tanous return; 35391da66f75SEd Tanous } 3540e855dd28SJason M. Bills 3541043a0536SJohnathan Mantey // Verify the file name parameter is correct 3542043a0536SJohnathan Mantey if (fileName != dbusFilename) 3543043a0536SJohnathan Mantey { 35449db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3545043a0536SJohnathan Mantey return; 3546043a0536SJohnathan Mantey } 3547043a0536SJohnathan Mantey 3548043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3549043a0536SJohnathan Mantey { 35509db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3551043a0536SJohnathan Mantey return; 3552043a0536SJohnathan Mantey } 3553002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3554002d39b4SEd Tanous asyncResp->res.body() = 3555002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3556043a0536SJohnathan Mantey 35577e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 35587e860f15SJohn Edward Broadbent // from a browser 3559d9f6c621SEd Tanous asyncResp->res.addHeader( 3560d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 35611da66f75SEd Tanous }; 3562d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3563d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3564d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3565d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 35667e860f15SJohn Edward Broadbent }); 35671da66f75SEd Tanous } 35681da66f75SEd Tanous 3569c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3570c5a4c82aSJason M. Bills { 3571c5a4c82aSJason M. Bills onDemand, 3572c5a4c82aSJason M. Bills telemetry, 3573c5a4c82aSJason M. Bills invalid, 3574c5a4c82aSJason M. Bills }; 3575c5a4c82aSJason M. Bills 357626ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3577c5a4c82aSJason M. Bills { 3578c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3579c5a4c82aSJason M. Bills { 3580c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3581c5a4c82aSJason M. Bills } 3582c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3583c5a4c82aSJason M. Bills { 3584c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3585c5a4c82aSJason M. Bills } 3586c5a4c82aSJason M. Bills 3587c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3588c5a4c82aSJason M. Bills } 3589c5a4c82aSJason M. Bills 35907e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 35911da66f75SEd Tanous { 35923946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 35933946028dSAppaRao Puli // method for security reasons. 35940fda0f12SGeorge Liu BMCWEB_ROUTE( 35950fda0f12SGeorge Liu app, 359622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3597ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3598ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3599432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3600002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3601002d39b4SEd Tanous [&app](const crow::Request& req, 360222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 360322d268cbSEd Tanous const std::string& systemName) { 36043ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 360545ca1b86SEd Tanous { 360645ca1b86SEd Tanous return; 360745ca1b86SEd Tanous } 360822d268cbSEd Tanous 36097f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 36107f3e84a1SEd Tanous { 36117f3e84a1SEd Tanous // Option currently returns no systems. TBD 36127f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36137f3e84a1SEd Tanous systemName); 36147f3e84a1SEd Tanous return; 36157f3e84a1SEd Tanous } 361622d268cbSEd Tanous if (systemName != "system") 361722d268cbSEd Tanous { 361822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 361922d268cbSEd Tanous systemName); 362022d268cbSEd Tanous return; 362122d268cbSEd Tanous } 362222d268cbSEd Tanous 36238e6c099aSJason M. Bills std::string diagnosticDataType; 36248e6c099aSJason M. Bills std::string oemDiagnosticDataType; 362515ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3626002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3627002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 36288e6c099aSJason M. Bills { 36298e6c099aSJason M. Bills return; 36308e6c099aSJason M. Bills } 36318e6c099aSJason M. Bills 36328e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 36338e6c099aSJason M. Bills { 363462598e31SEd Tanous BMCWEB_LOG_ERROR( 363562598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 36368e6c099aSJason M. Bills messages::actionParameterValueFormatError( 36378e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 36388e6c099aSJason M. Bills "CollectDiagnosticData"); 36398e6c099aSJason M. Bills return; 36408e6c099aSJason M. Bills } 36418e6c099aSJason M. Bills 3642c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3643c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3644c5a4c82aSJason M. Bills 3645c5a4c82aSJason M. Bills std::string iface; 3646c5a4c82aSJason M. Bills std::string method; 3647c5a4c82aSJason M. Bills std::string taskMatchStr; 3648c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3649c5a4c82aSJason M. Bills { 3650c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3651c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3652c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3653c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3654c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3655c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3656c5a4c82aSJason M. Bills } 3657c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3658c5a4c82aSJason M. Bills { 3659c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3660c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3661c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3662c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3663c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3664c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3665c5a4c82aSJason M. Bills } 3666c5a4c82aSJason M. Bills else 3667c5a4c82aSJason M. Bills { 366862598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 366962598e31SEd Tanous oemDiagnosticDataType); 3670c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3671002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3672002d39b4SEd Tanous "CollectDiagnosticData"); 3673c5a4c82aSJason M. Bills return; 3674c5a4c82aSJason M. Bills } 3675c5a4c82aSJason M. Bills 3676c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3677c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 36785e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 367998be3e39SEd Tanous const std::string&) mutable { 36801da66f75SEd Tanous if (ec) 36811da66f75SEd Tanous { 3682002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 36831da66f75SEd Tanous { 3684f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 36851da66f75SEd Tanous } 36864363d3b2SJason M. Bills else if (ec.value() == 36874363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 36884363d3b2SJason M. Bills { 3689002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3690002d39b4SEd Tanous "60"); 36914363d3b2SJason M. Bills } 36921da66f75SEd Tanous else 36931da66f75SEd Tanous { 3694f12894f8SJason M. Bills messages::internalError(asyncResp->res); 36951da66f75SEd Tanous } 36961da66f75SEd Tanous return; 36971da66f75SEd Tanous } 3698002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 36998b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3700002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 37018b24275dSEd Tanous if (!ec2) 370266afe4faSJames Feist { 3703002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3704e5d5006bSJames Feist std::to_string(taskData->index))); 3705831d6b09SJames Feist taskData->state = "Completed"; 370666afe4faSJames Feist } 370732898ceaSJames Feist return task::completed; 370866afe4faSJames Feist }, 3709c5a4c82aSJason M. Bills taskMatchStr); 3710c5a4c82aSJason M. Bills 371146229577SJames Feist task->startTimer(std::chrono::minutes(5)); 371246229577SJames Feist task->populateResp(asyncResp->res); 371398be3e39SEd Tanous task->payload.emplace(std::move(payload)); 37141da66f75SEd Tanous }; 37158e6c099aSJason M. Bills 37161da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3717002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3718002d39b4SEd Tanous iface, method); 37197e860f15SJohn Edward Broadbent }); 37206eda7685SKenny L. Ku } 37216eda7685SKenny L. Ku 3722cb92c03bSAndrew Geissler /** 3723cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3724cb92c03bSAndrew Geissler */ 37257e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3726cb92c03bSAndrew Geissler { 3727cb92c03bSAndrew Geissler /** 3728cb92c03bSAndrew Geissler * Function handles POST method request. 3729cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3730cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3731cb92c03bSAndrew Geissler */ 37327e860f15SJohn Edward Broadbent 37330fda0f12SGeorge Liu BMCWEB_ROUTE( 37340fda0f12SGeorge Liu app, 373522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3736ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 37377e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 373845ca1b86SEd Tanous [&app](const crow::Request& req, 373922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 374022d268cbSEd Tanous const std::string& systemName) { 37413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 374245ca1b86SEd Tanous { 374345ca1b86SEd Tanous return; 374445ca1b86SEd Tanous } 37457f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37467f3e84a1SEd Tanous { 37477f3e84a1SEd Tanous // Option currently returns no systems. TBD 37487f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37497f3e84a1SEd Tanous systemName); 37507f3e84a1SEd Tanous return; 37517f3e84a1SEd Tanous } 375222d268cbSEd Tanous if (systemName != "system") 375322d268cbSEd Tanous { 375422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 375522d268cbSEd Tanous systemName); 375622d268cbSEd Tanous return; 375722d268cbSEd Tanous } 375862598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3759cb92c03bSAndrew Geissler 3760cb92c03bSAndrew Geissler // Process response from Logging service. 37615e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 376262598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3763cb92c03bSAndrew Geissler if (ec) 3764cb92c03bSAndrew Geissler { 3765cb92c03bSAndrew Geissler // TODO Handle for specific error code 376662598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3767cb92c03bSAndrew Geissler asyncResp->res.result( 3768cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3769cb92c03bSAndrew Geissler return; 3770cb92c03bSAndrew Geissler } 3771cb92c03bSAndrew Geissler 3772002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3773cb92c03bSAndrew Geissler }; 3774cb92c03bSAndrew Geissler 3775cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3776cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 37772c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3778cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3779cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 37807e860f15SJohn Edward Broadbent }); 3781cb92c03bSAndrew Geissler } 3782a3316fc6SZhikuiRen 3783a3316fc6SZhikuiRen /**************************************************** 3784a3316fc6SZhikuiRen * Redfish PostCode interfaces 3785a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3786a3316fc6SZhikuiRen ******************************************************/ 37877e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3788a3316fc6SZhikuiRen { 378922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3790ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3791002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3792002d39b4SEd Tanous [&app](const crow::Request& req, 379322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 379422d268cbSEd Tanous const std::string& systemName) { 37953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 379645ca1b86SEd Tanous { 379745ca1b86SEd Tanous return; 379845ca1b86SEd Tanous } 37997f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38007f3e84a1SEd Tanous { 38017f3e84a1SEd Tanous // Option currently returns no systems. TBD 38027f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38037f3e84a1SEd Tanous systemName); 38047f3e84a1SEd Tanous return; 38057f3e84a1SEd Tanous } 380622d268cbSEd Tanous if (systemName != "system") 380722d268cbSEd Tanous { 380822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 380922d268cbSEd Tanous systemName); 381022d268cbSEd Tanous return; 381122d268cbSEd Tanous } 38121476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 38131476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 38141476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3815b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 38161476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 38171476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3818ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 38191476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 38201476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 38211476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 38227c8c4058STejas Patil 38237c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 38242b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 38250fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 38267c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 38277c8c4058STejas Patil redfishDateTimeOffset.second; 38287c8c4058STejas Patil 3829a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 38307e860f15SJohn Edward Broadbent {"target", 38310fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 38327e860f15SJohn Edward Broadbent }); 3833a3316fc6SZhikuiRen } 3834a3316fc6SZhikuiRen 38357e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3836a3316fc6SZhikuiRen { 38370fda0f12SGeorge Liu BMCWEB_ROUTE( 38380fda0f12SGeorge Liu app, 383922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3840ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3841ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3842432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 38437e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 384445ca1b86SEd Tanous [&app](const crow::Request& req, 384522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 384622d268cbSEd Tanous const std::string& systemName) { 38473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 384845ca1b86SEd Tanous { 384945ca1b86SEd Tanous return; 385045ca1b86SEd Tanous } 38517f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38527f3e84a1SEd Tanous { 38537f3e84a1SEd Tanous // Option currently returns no systems. TBD 38547f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38557f3e84a1SEd Tanous systemName); 38567f3e84a1SEd Tanous return; 38577f3e84a1SEd Tanous } 385822d268cbSEd Tanous if (systemName != "system") 385922d268cbSEd Tanous { 386022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 386122d268cbSEd Tanous systemName); 386222d268cbSEd Tanous return; 386322d268cbSEd Tanous } 386462598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3865a3316fc6SZhikuiRen 3866a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3867a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 38685e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3869a3316fc6SZhikuiRen if (ec) 3870a3316fc6SZhikuiRen { 3871a3316fc6SZhikuiRen // TODO Handle for specific error code 387262598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 387362598e31SEd Tanous ec); 3874002d39b4SEd Tanous asyncResp->res.result( 3875002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3876a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3877a3316fc6SZhikuiRen return; 3878a3316fc6SZhikuiRen } 387918fc70c0STony Lee messages::success(asyncResp->res); 3880a3316fc6SZhikuiRen }, 388115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 388215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3883a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 38847e860f15SJohn Edward Broadbent }); 3885a3316fc6SZhikuiRen } 3886a3316fc6SZhikuiRen 38876f284d24SJiaqing Zhao /** 38886f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 38896f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 38906f284d24SJiaqing Zhao * 38916f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 38926f284d24SJiaqing Zhao * @param[out] currentValue Current value 38936f284d24SJiaqing Zhao * @param[out] index Index value 38946f284d24SJiaqing Zhao * 38956f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 38966f284d24SJiaqing Zhao */ 38976f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 38986f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 38996f284d24SJiaqing Zhao { 39006f284d24SJiaqing Zhao std::vector<std::string> split; 390150ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 39026f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 39036f284d24SJiaqing Zhao { 39046f284d24SJiaqing Zhao return false; 39056f284d24SJiaqing Zhao } 39066f284d24SJiaqing Zhao 390784396af9SPatrick Williams auto start = std::next(split[0].begin()); 390884396af9SPatrick Williams auto end = split[0].end(); 390984396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 39106f284d24SJiaqing Zhao 391184396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 39126f284d24SJiaqing Zhao { 39136f284d24SJiaqing Zhao return false; 39146f284d24SJiaqing Zhao } 39156f284d24SJiaqing Zhao 391684396af9SPatrick Williams start = split[1].begin(); 391784396af9SPatrick Williams end = split[1].end(); 39186f284d24SJiaqing Zhao 391984396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 39206f284d24SJiaqing Zhao 392184396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 39226f284d24SJiaqing Zhao } 39236f284d24SJiaqing Zhao 39246f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3925ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39266c9a279eSManojkiran Eda const boost::container::flat_map< 39276c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3928a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3929a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3930a3316fc6SZhikuiRen { 3931a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3932fffb8c1fSEd Tanous const registries::Message* message = 3933fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3934a3316fc6SZhikuiRen 3935a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3936a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 39376c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 39386c9a279eSManojkiran Eda code : postcode) 3939a3316fc6SZhikuiRen { 3940a3316fc6SZhikuiRen currentCodeIndex++; 3941a3316fc6SZhikuiRen std::string postcodeEntryID = 3942a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3943a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3944a3316fc6SZhikuiRen 3945a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3946a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3947a3316fc6SZhikuiRen 3948a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3949a3316fc6SZhikuiRen { // already incremented 3950a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3951a3316fc6SZhikuiRen } 3952a3316fc6SZhikuiRen else 3953a3316fc6SZhikuiRen { 3954a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3955a3316fc6SZhikuiRen } 3956a3316fc6SZhikuiRen 3957a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3958a3316fc6SZhikuiRen // not fall between top and skip 3959a3316fc6SZhikuiRen if ((codeIndex == 0) && 3960a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3961a3316fc6SZhikuiRen { 3962a3316fc6SZhikuiRen continue; 3963a3316fc6SZhikuiRen } 3964a3316fc6SZhikuiRen 39654e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3966a3316fc6SZhikuiRen // currentIndex 3967a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3968a3316fc6SZhikuiRen { 3969a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3970a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3971a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3972a3316fc6SZhikuiRen continue; 3973a3316fc6SZhikuiRen } 3974a3316fc6SZhikuiRen 3975a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3976a3316fc6SZhikuiRen // index 3977a3316fc6SZhikuiRen 3978a3316fc6SZhikuiRen // Get the Created time from the timestamp 3979a3316fc6SZhikuiRen std::string entryTimeStr; 39802a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3981a3316fc6SZhikuiRen 3982a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3983a3316fc6SZhikuiRen std::ostringstream hexCode; 3984a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 39856c9a279eSManojkiran Eda << std::get<0>(code.second); 3986a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3987a3316fc6SZhikuiRen // Set Fixed -Point Notation 3988a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3989a3316fc6SZhikuiRen // Set precision to 4 digits 3990a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3991a3316fc6SZhikuiRen // Add double to stream 3992a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3993a3316fc6SZhikuiRen 39941e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 39951e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 39961e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3997a3316fc6SZhikuiRen 39981e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 39991e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 40001e6deaf6SEd Tanous 40011e6deaf6SEd Tanous std::string msg = 40021e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 40031e6deaf6SEd Tanous if (msg.empty()) 4004a3316fc6SZhikuiRen { 40051e6deaf6SEd Tanous messages::internalError(asyncResp->res); 40061e6deaf6SEd Tanous return false; 4007a3316fc6SZhikuiRen } 4008a3316fc6SZhikuiRen 4009d4342a92STim Lee // Get Severity template from message registry 4010d4342a92STim Lee std::string severity; 4011d4342a92STim Lee if (message != nullptr) 4012d4342a92STim Lee { 40135f2b84eeSEd Tanous severity = message->messageSeverity; 4014d4342a92STim Lee } 4015d4342a92STim Lee 40166f284d24SJiaqing Zhao // Format entry 40176f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 40189c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4019ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 4020ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 4021ef4c65b7SEd Tanous postcodeEntryID); 402284afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 402384afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 402484afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 402584afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 40261e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 402784afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 402884afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 402984afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 4030647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 4031647b3cdcSGeorge Liu { 4032647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 4033647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 4034647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 4035647b3cdcSGeorge Liu } 40366f284d24SJiaqing Zhao 40376f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 40386f284d24SJiaqing Zhao // that entry in this case 40396f284d24SJiaqing Zhao if (codeIndex != 0) 40406f284d24SJiaqing Zhao { 4041ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 40426f284d24SJiaqing Zhao return true; 4043a3316fc6SZhikuiRen } 40446f284d24SJiaqing Zhao 4045ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 4046b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 40476f284d24SJiaqing Zhao } 40486f284d24SJiaqing Zhao 40496f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 40506f284d24SJiaqing Zhao return false; 4051a3316fc6SZhikuiRen } 4052a3316fc6SZhikuiRen 4053ac106bf6SEd Tanous static void 4054ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40556f284d24SJiaqing Zhao const std::string& entryId) 4056a3316fc6SZhikuiRen { 40576f284d24SJiaqing Zhao uint16_t bootIndex = 0; 40586f284d24SJiaqing Zhao uint64_t codeIndex = 0; 40596f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 40606f284d24SJiaqing Zhao { 40616f284d24SJiaqing Zhao // Requested ID was not found 4062ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40636f284d24SJiaqing Zhao return; 40646f284d24SJiaqing Zhao } 40656f284d24SJiaqing Zhao 40666f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 40676f284d24SJiaqing Zhao { 40686f284d24SJiaqing Zhao // 0 is an invalid index 4069ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40706f284d24SJiaqing Zhao return; 40716f284d24SJiaqing Zhao } 40726f284d24SJiaqing Zhao 4073a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4074ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 40755e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 40766c9a279eSManojkiran Eda const boost::container::flat_map< 40776c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 40786c9a279eSManojkiran Eda postcode) { 4079a3316fc6SZhikuiRen if (ec) 4080a3316fc6SZhikuiRen { 408162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4082ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4083a3316fc6SZhikuiRen return; 4084a3316fc6SZhikuiRen } 4085a3316fc6SZhikuiRen 4086a3316fc6SZhikuiRen if (postcode.empty()) 4087a3316fc6SZhikuiRen { 4088ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 4089a3316fc6SZhikuiRen return; 4090a3316fc6SZhikuiRen } 4091a3316fc6SZhikuiRen 4092ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 40936f284d24SJiaqing Zhao { 4094ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40956f284d24SJiaqing Zhao return; 40966f284d24SJiaqing Zhao } 4097a3316fc6SZhikuiRen }, 409815124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 409915124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4100a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4101a3316fc6SZhikuiRen bootIndex); 4102a3316fc6SZhikuiRen } 4103a3316fc6SZhikuiRen 4104ac106bf6SEd Tanous static void 4105ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4106ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4107ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4108a3316fc6SZhikuiRen { 4109a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4110ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 41115e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 41126c9a279eSManojkiran Eda const boost::container::flat_map< 41136c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41146c9a279eSManojkiran Eda postcode) { 4115a3316fc6SZhikuiRen if (ec) 4116a3316fc6SZhikuiRen { 411762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4118ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4119a3316fc6SZhikuiRen return; 4120a3316fc6SZhikuiRen } 4121a3316fc6SZhikuiRen 4122a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4123a3316fc6SZhikuiRen if (!postcode.empty()) 4124a3316fc6SZhikuiRen { 4125a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 41263648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4127a3316fc6SZhikuiRen { 412889492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 412989492a15SPatrick Williams entryCount) - 41303648c8beSEd Tanous entryCount; 4131a3316fc6SZhikuiRen uint64_t thisBootTop = 41323648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 41333648c8beSEd Tanous entryCount; 4134a3316fc6SZhikuiRen 4135ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4136ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4137a3316fc6SZhikuiRen } 4138ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4139a3316fc6SZhikuiRen } 4140a3316fc6SZhikuiRen 4141a3316fc6SZhikuiRen // continue to previous bootIndex 4142a3316fc6SZhikuiRen if (bootIndex < bootCount) 4143a3316fc6SZhikuiRen { 4144ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4145a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4146a3316fc6SZhikuiRen } 414781584abeSJiaqing Zhao else if (skip + top < endCount) 4148a3316fc6SZhikuiRen { 4149ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 41500fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 4151a3316fc6SZhikuiRen std::to_string(skip + top); 4152a3316fc6SZhikuiRen } 4153a3316fc6SZhikuiRen }, 415415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 415515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4156a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4157a3316fc6SZhikuiRen bootIndex); 4158a3316fc6SZhikuiRen } 4159a3316fc6SZhikuiRen 41608d1b46d7Szhanghch05 static void 4161ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 41623648c8beSEd Tanous size_t skip, size_t top) 4163a3316fc6SZhikuiRen { 4164a3316fc6SZhikuiRen uint64_t entryCount = 0; 41651e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 41661e1e598dSJonathan Doman *crow::connections::systemBus, 41671e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 41681e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 41691e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4170ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 41711e1e598dSJonathan Doman const uint16_t bootCount) { 4172a3316fc6SZhikuiRen if (ec) 4173a3316fc6SZhikuiRen { 417462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4175ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4176a3316fc6SZhikuiRen return; 4177a3316fc6SZhikuiRen } 4178ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 41791e1e598dSJonathan Doman }); 4180a3316fc6SZhikuiRen } 4181a3316fc6SZhikuiRen 41827e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4183a3316fc6SZhikuiRen { 41847e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 418522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4186ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 41877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 418845ca1b86SEd Tanous [&app](const crow::Request& req, 418922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 419022d268cbSEd Tanous const std::string& systemName) { 4191c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4192c937d2bfSEd Tanous .canDelegateTop = true, 4193c937d2bfSEd Tanous .canDelegateSkip = true, 4194c937d2bfSEd Tanous }; 4195c937d2bfSEd Tanous query_param::Query delegatedQuery; 4196c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 41973ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 419845ca1b86SEd Tanous { 419945ca1b86SEd Tanous return; 420045ca1b86SEd Tanous } 42017f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42027f3e84a1SEd Tanous { 42037f3e84a1SEd Tanous // Option currently returns no systems. TBD 42047f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42057f3e84a1SEd Tanous systemName); 42067f3e84a1SEd Tanous return; 42077f3e84a1SEd Tanous } 420822d268cbSEd Tanous 420922d268cbSEd Tanous if (systemName != "system") 421022d268cbSEd Tanous { 421122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 421222d268cbSEd Tanous systemName); 421322d268cbSEd Tanous return; 421422d268cbSEd Tanous } 4215a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4216a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4217a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4218a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4219a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4220a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4221a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4222a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4223a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 42243648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 42255143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 42263648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 42277e860f15SJohn Edward Broadbent }); 4228a3316fc6SZhikuiRen } 4229a3316fc6SZhikuiRen 4230647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4231647b3cdcSGeorge Liu { 42320fda0f12SGeorge Liu BMCWEB_ROUTE( 42330fda0f12SGeorge Liu app, 423422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4235647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4236647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 423745ca1b86SEd Tanous [&app](const crow::Request& req, 4238647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 423922d268cbSEd Tanous const std::string& systemName, 4240647b3cdcSGeorge Liu const std::string& postCodeID) { 42413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 424245ca1b86SEd Tanous { 424345ca1b86SEd Tanous return; 424445ca1b86SEd Tanous } 424572e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 424699351cd8SEd Tanous req.getHeaderValue("Accept"), 42474a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4248647b3cdcSGeorge Liu { 4249002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4250647b3cdcSGeorge Liu return; 4251647b3cdcSGeorge Liu } 42527f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42537f3e84a1SEd Tanous { 42547f3e84a1SEd Tanous // Option currently returns no systems. TBD 42557f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42567f3e84a1SEd Tanous systemName); 42577f3e84a1SEd Tanous return; 42587f3e84a1SEd Tanous } 425922d268cbSEd Tanous if (systemName != "system") 426022d268cbSEd Tanous { 426122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 426222d268cbSEd Tanous systemName); 426322d268cbSEd Tanous return; 426422d268cbSEd Tanous } 4265647b3cdcSGeorge Liu 4266647b3cdcSGeorge Liu uint64_t currentValue = 0; 4267647b3cdcSGeorge Liu uint16_t index = 0; 4268647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4269647b3cdcSGeorge Liu { 4270002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4271647b3cdcSGeorge Liu return; 4272647b3cdcSGeorge Liu } 4273647b3cdcSGeorge Liu 4274647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4275647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 42765e7e2dc5SEd Tanous const boost::system::error_code& ec, 4277002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4278002d39b4SEd Tanous postcodes) { 4279647b3cdcSGeorge Liu if (ec.value() == EBADR) 4280647b3cdcSGeorge Liu { 4281002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4282002d39b4SEd Tanous postCodeID); 4283647b3cdcSGeorge Liu return; 4284647b3cdcSGeorge Liu } 4285647b3cdcSGeorge Liu if (ec) 4286647b3cdcSGeorge Liu { 428762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4288647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4289647b3cdcSGeorge Liu return; 4290647b3cdcSGeorge Liu } 4291647b3cdcSGeorge Liu 4292647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4293002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4294647b3cdcSGeorge Liu { 429562598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4296002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4297002d39b4SEd Tanous postCodeID); 4298647b3cdcSGeorge Liu return; 4299647b3cdcSGeorge Liu } 4300647b3cdcSGeorge Liu 43019eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 430246ff87baSEd Tanous if (c.empty()) 4303647b3cdcSGeorge Liu { 430462598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4305002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4306002d39b4SEd Tanous postCodeID); 4307647b3cdcSGeorge Liu return; 4308647b3cdcSGeorge Liu } 430946ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 431046ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 431146ff87baSEd Tanous std::string_view strData(d, c.size()); 4312647b3cdcSGeorge Liu 4313d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4314647b3cdcSGeorge Liu "application/octet-stream"); 4315d9f6c621SEd Tanous asyncResp->res.addHeader( 4316d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4317002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4318647b3cdcSGeorge Liu }, 4319647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4320647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4321002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4322647b3cdcSGeorge Liu }); 4323647b3cdcSGeorge Liu } 4324647b3cdcSGeorge Liu 43257e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4326a3316fc6SZhikuiRen { 43277e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 432822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4329ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 43307e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 433145ca1b86SEd Tanous [&app](const crow::Request& req, 43327e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 433322d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 43343ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 433545ca1b86SEd Tanous { 433645ca1b86SEd Tanous return; 433745ca1b86SEd Tanous } 43387f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 43397f3e84a1SEd Tanous { 43407f3e84a1SEd Tanous // Option currently returns no systems. TBD 43417f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 43427f3e84a1SEd Tanous systemName); 43437f3e84a1SEd Tanous return; 43447f3e84a1SEd Tanous } 434522d268cbSEd Tanous if (systemName != "system") 434622d268cbSEd Tanous { 434722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 434822d268cbSEd Tanous systemName); 434922d268cbSEd Tanous return; 435022d268cbSEd Tanous } 435122d268cbSEd Tanous 43526f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 43537e860f15SJohn Edward Broadbent }); 4354a3316fc6SZhikuiRen } 4355a3316fc6SZhikuiRen 43561da66f75SEd Tanous } // namespace redfish 4357