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> 5326702d01SEd Tanous #include <span> 54cd225da8SJason M. Bills #include <string_view> 55abf2add6SEd Tanous #include <variant> 561da66f75SEd Tanous 571da66f75SEd Tanous namespace redfish 581da66f75SEd Tanous { 591da66f75SEd Tanous 6089492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6189492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6289492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6389492a15SPatrick Williams constexpr const char* deleteAllInterface = 645b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6589492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 66424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6789492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 686eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 691da66f75SEd Tanous 708e31778eSAsmitha Karunanithi enum class DumpCreationProgress 718e31778eSAsmitha Karunanithi { 728e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 738e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 748e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 758e31778eSAsmitha Karunanithi }; 768e31778eSAsmitha Karunanithi 77f6150403SJames Feist namespace fs = std::filesystem; 781da66f75SEd Tanous 79cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 80cb92c03bSAndrew Geissler { 81d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 82d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 85cb92c03bSAndrew Geissler { 86cb92c03bSAndrew Geissler return "Critical"; 87cb92c03bSAndrew Geissler } 883174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 89d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 90d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 91cb92c03bSAndrew Geissler { 92cb92c03bSAndrew Geissler return "OK"; 93cb92c03bSAndrew Geissler } 943174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 95cb92c03bSAndrew Geissler { 96cb92c03bSAndrew Geissler return "Warning"; 97cb92c03bSAndrew Geissler } 98cb92c03bSAndrew Geissler return ""; 99cb92c03bSAndrew Geissler } 100cb92c03bSAndrew Geissler 1019017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1029017faf2SAbhishek Patel { 1039017faf2SAbhishek Patel std::optional<bool> notifyAction; 1049017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1059017faf2SAbhishek Patel { 1069017faf2SAbhishek Patel notifyAction = true; 1079017faf2SAbhishek Patel } 1089017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1099017faf2SAbhishek Patel { 1109017faf2SAbhishek Patel notifyAction = false; 1119017faf2SAbhishek Patel } 1129017faf2SAbhishek Patel 1139017faf2SAbhishek Patel return notifyAction; 1149017faf2SAbhishek Patel } 1159017faf2SAbhishek Patel 1167e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 11726ccae32SEd Tanous std::string_view field, 11839e77504SEd Tanous std::string_view& contents) 11916428a1aSJason M. Bills { 12016428a1aSJason M. Bills const char* data = nullptr; 12116428a1aSJason M. Bills size_t length = 0; 12216428a1aSJason M. Bills int ret = 0; 12316428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 12446ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 12546ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 12646ff87baSEd Tanous 12746ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 12816428a1aSJason M. Bills if (ret < 0) 12916428a1aSJason M. Bills { 13016428a1aSJason M. Bills return ret; 13116428a1aSJason M. Bills } 13239e77504SEd Tanous contents = std::string_view(data, length); 13316428a1aSJason M. Bills // Only use the content after the "=" character. 13481ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 13516428a1aSJason M. Bills return ret; 13616428a1aSJason M. Bills } 13716428a1aSJason M. Bills 1387e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 13926ccae32SEd Tanous std::string_view field, const int& base, 14026ccae32SEd Tanous long int& contents) 14116428a1aSJason M. Bills { 14216428a1aSJason M. Bills int ret = 0; 14339e77504SEd Tanous std::string_view metadata; 14416428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14516428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 14616428a1aSJason M. Bills if (ret < 0) 14716428a1aSJason M. Bills { 14816428a1aSJason M. Bills return ret; 14916428a1aSJason M. Bills } 150b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15116428a1aSJason M. Bills return ret; 15216428a1aSJason M. Bills } 15316428a1aSJason M. Bills 1547e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1557e860f15SJohn Edward Broadbent std::string& entryTimestamp) 156a3316fc6SZhikuiRen { 157a3316fc6SZhikuiRen int ret = 0; 158a3316fc6SZhikuiRen uint64_t timestamp = 0; 159a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 160a3316fc6SZhikuiRen if (ret < 0) 161a3316fc6SZhikuiRen { 162a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 163a3316fc6SZhikuiRen << 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 { 18616428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 18716428a1aSJason M. Bills << strerror(-ret); 18816428a1aSJason M. Bills return false; 18916428a1aSJason M. Bills } 19016428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 19116428a1aSJason M. Bills if (curTs == prevTs) 19216428a1aSJason M. Bills { 19316428a1aSJason M. Bills index++; 19416428a1aSJason M. Bills } 19516428a1aSJason M. Bills else 19616428a1aSJason M. Bills { 19716428a1aSJason M. Bills // Otherwise, reset it 19816428a1aSJason M. Bills index = 0; 19916428a1aSJason M. Bills } 20016428a1aSJason M. Bills // Save the timestamp 20116428a1aSJason M. Bills prevTs = curTs; 20216428a1aSJason M. Bills 20316428a1aSJason M. Bills entryID = std::to_string(curTs); 20416428a1aSJason M. Bills if (index > 0) 20516428a1aSJason M. Bills { 20616428a1aSJason M. Bills entryID += "_" + std::to_string(index); 20716428a1aSJason M. Bills } 20816428a1aSJason M. Bills return true; 20916428a1aSJason M. Bills } 21016428a1aSJason M. Bills 211e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 212e85d6b16SJason M. Bills const bool firstEntry = true) 21395820184SJason M. Bills { 214271584abSEd Tanous static time_t prevTs = 0; 21595820184SJason M. Bills static int index = 0; 216e85d6b16SJason M. Bills if (firstEntry) 217e85d6b16SJason M. Bills { 218e85d6b16SJason M. Bills prevTs = 0; 219e85d6b16SJason M. Bills } 220e85d6b16SJason M. Bills 22195820184SJason M. Bills // Get the entry timestamp 222271584abSEd Tanous std::time_t curTs = 0; 22395820184SJason M. Bills std::tm timeStruct = {}; 22495820184SJason M. Bills std::istringstream entryStream(logEntry); 22595820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 22695820184SJason M. Bills { 22795820184SJason M. Bills curTs = std::mktime(&timeStruct); 22895820184SJason M. Bills } 22995820184SJason M. Bills // If the timestamp isn't unique, increment the index 23095820184SJason M. Bills if (curTs == prevTs) 23195820184SJason M. Bills { 23295820184SJason M. Bills index++; 23395820184SJason M. Bills } 23495820184SJason M. Bills else 23595820184SJason M. Bills { 23695820184SJason M. Bills // Otherwise, reset it 23795820184SJason M. Bills index = 0; 23895820184SJason M. Bills } 23995820184SJason M. Bills // Save the timestamp 24095820184SJason M. Bills prevTs = curTs; 24195820184SJason M. Bills 24295820184SJason M. Bills entryID = std::to_string(curTs); 24395820184SJason M. Bills if (index > 0) 24495820184SJason M. Bills { 24595820184SJason M. Bills entryID += "_" + std::to_string(index); 24695820184SJason M. Bills } 24795820184SJason M. Bills return true; 24895820184SJason M. Bills } 24995820184SJason M. Bills 2507e860f15SJohn Edward Broadbent inline static bool 2518d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2528d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2538d1b46d7Szhanghch05 uint64_t& index) 25416428a1aSJason M. Bills { 25516428a1aSJason M. Bills if (entryID.empty()) 25616428a1aSJason M. Bills { 25716428a1aSJason M. Bills return false; 25816428a1aSJason M. Bills } 25916428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 26039e77504SEd Tanous std::string_view tsStr(entryID); 26116428a1aSJason M. Bills 26281ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 26371d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 26416428a1aSJason M. Bills { 26516428a1aSJason M. Bills // Timestamp has an index 26616428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 26739e77504SEd Tanous std::string_view indexStr(entryID); 26816428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 26984396af9SPatrick Williams auto [ptr, ec] = std::from_chars(indexStr.begin(), indexStr.end(), 27084396af9SPatrick Williams index); 271c0bd5e4bSEd Tanous if (ec != std::errc()) 27216428a1aSJason M. Bills { 2739db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 27416428a1aSJason M. Bills return false; 27516428a1aSJason M. Bills } 27616428a1aSJason M. Bills } 27716428a1aSJason M. Bills // Timestamp has no index 27884396af9SPatrick Williams auto [ptr, ec] = std::from_chars(tsStr.begin(), tsStr.end(), timestamp); 279c0bd5e4bSEd Tanous if (ec != std::errc()) 28016428a1aSJason M. Bills { 2819db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 28216428a1aSJason M. Bills return false; 28316428a1aSJason M. Bills } 28416428a1aSJason M. Bills return true; 28516428a1aSJason M. Bills } 28616428a1aSJason M. Bills 28795820184SJason M. Bills static bool 28895820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 28995820184SJason M. Bills { 29095820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 29195820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 29295820184SJason M. Bills 29395820184SJason M. Bills // Loop through the directory looking for redfish log files 29495820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 29595820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 29695820184SJason M. Bills { 29795820184SJason M. Bills // If we find a redfish log file, save the path 29895820184SJason M. Bills std::string filename = dirEnt.path().filename(); 29911ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 30095820184SJason M. Bills { 30195820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 30295820184SJason M. Bills } 30395820184SJason M. Bills } 30495820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 30595820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 30695820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 30795820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 30895820184SJason M. Bills 30995820184SJason M. Bills return !redfishLogFiles.empty(); 31095820184SJason M. Bills } 31195820184SJason M. Bills 31268dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 31368dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 31468dd075aSAsmitha Karunanithi { 31568dd075aSAsmitha Karunanithi if (originatorType == 31668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 31768dd075aSAsmitha Karunanithi { 31868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 31968dd075aSAsmitha Karunanithi } 32068dd075aSAsmitha Karunanithi if (originatorType == 32168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 32268dd075aSAsmitha Karunanithi { 32368dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 32468dd075aSAsmitha Karunanithi } 32568dd075aSAsmitha Karunanithi if (originatorType == 32668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 32768dd075aSAsmitha Karunanithi { 32868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 32968dd075aSAsmitha Karunanithi } 33068dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 33168dd075aSAsmitha Karunanithi } 33268dd075aSAsmitha Karunanithi 333aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3342d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 335c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 33668dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 337aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 338aefe3786SClaire Weinan { 339aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 340aefe3786SClaire Weinan { 341aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 342aefe3786SClaire Weinan { 343aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 344aefe3786SClaire Weinan { 345aefe3786SClaire Weinan if (propertyMap.first == "Status") 346aefe3786SClaire Weinan { 347aefe3786SClaire Weinan const auto* status = 348aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 349aefe3786SClaire Weinan if (status == nullptr) 350aefe3786SClaire Weinan { 351aefe3786SClaire Weinan messages::internalError(asyncResp->res); 352aefe3786SClaire Weinan break; 353aefe3786SClaire Weinan } 354aefe3786SClaire Weinan dumpStatus = *status; 355aefe3786SClaire Weinan } 356aefe3786SClaire Weinan } 357aefe3786SClaire Weinan } 358aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 359aefe3786SClaire Weinan { 360aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 361aefe3786SClaire Weinan { 362aefe3786SClaire Weinan if (propertyMap.first == "Size") 363aefe3786SClaire Weinan { 364aefe3786SClaire Weinan const auto* sizePtr = 365aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 366aefe3786SClaire Weinan if (sizePtr == nullptr) 367aefe3786SClaire Weinan { 368aefe3786SClaire Weinan messages::internalError(asyncResp->res); 369aefe3786SClaire Weinan break; 370aefe3786SClaire Weinan } 371aefe3786SClaire Weinan size = *sizePtr; 372aefe3786SClaire Weinan break; 373aefe3786SClaire Weinan } 374aefe3786SClaire Weinan } 375aefe3786SClaire Weinan } 376aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 377aefe3786SClaire Weinan { 378aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 379aefe3786SClaire Weinan { 380aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 381aefe3786SClaire Weinan { 382aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 383aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 384aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 385aefe3786SClaire Weinan { 386aefe3786SClaire Weinan messages::internalError(asyncResp->res); 387aefe3786SClaire Weinan break; 388aefe3786SClaire Weinan } 389c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 390aefe3786SClaire Weinan break; 391aefe3786SClaire Weinan } 392aefe3786SClaire Weinan } 393aefe3786SClaire Weinan } 39468dd075aSAsmitha Karunanithi else if (interfaceMap.first == 39568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 39668dd075aSAsmitha Karunanithi { 39768dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 39868dd075aSAsmitha Karunanithi { 39968dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 40068dd075aSAsmitha Karunanithi { 40168dd075aSAsmitha Karunanithi const std::string* id = 40268dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 40368dd075aSAsmitha Karunanithi if (id == nullptr) 40468dd075aSAsmitha Karunanithi { 40568dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 40668dd075aSAsmitha Karunanithi break; 40768dd075aSAsmitha Karunanithi } 40868dd075aSAsmitha Karunanithi originatorId = *id; 40968dd075aSAsmitha Karunanithi } 41068dd075aSAsmitha Karunanithi 41168dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 41268dd075aSAsmitha Karunanithi { 41368dd075aSAsmitha Karunanithi const std::string* type = 41468dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 41568dd075aSAsmitha Karunanithi if (type == nullptr) 41668dd075aSAsmitha Karunanithi { 41768dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 41868dd075aSAsmitha Karunanithi break; 41968dd075aSAsmitha Karunanithi } 42068dd075aSAsmitha Karunanithi 42168dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 42268dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 42368dd075aSAsmitha Karunanithi { 42468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 42568dd075aSAsmitha Karunanithi break; 42668dd075aSAsmitha Karunanithi } 42768dd075aSAsmitha Karunanithi } 42868dd075aSAsmitha Karunanithi } 42968dd075aSAsmitha Karunanithi } 430aefe3786SClaire Weinan } 431aefe3786SClaire Weinan } 432aefe3786SClaire Weinan 43321ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 434fdd26906SClaire Weinan { 435fdd26906SClaire Weinan std::string entriesPath; 436fdd26906SClaire Weinan 437fdd26906SClaire Weinan if (dumpType == "BMC") 438fdd26906SClaire Weinan { 439fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 440fdd26906SClaire Weinan } 441fdd26906SClaire Weinan else if (dumpType == "FaultLog") 442fdd26906SClaire Weinan { 443fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 444fdd26906SClaire Weinan } 445fdd26906SClaire Weinan else if (dumpType == "System") 446fdd26906SClaire Weinan { 447fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 448fdd26906SClaire Weinan } 449fdd26906SClaire Weinan else 450fdd26906SClaire Weinan { 451fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 452fdd26906SClaire Weinan << dumpType; 453fdd26906SClaire Weinan } 454fdd26906SClaire Weinan 455fdd26906SClaire Weinan // Returns empty string on error 456fdd26906SClaire Weinan return entriesPath; 457fdd26906SClaire Weinan } 458fdd26906SClaire Weinan 4598d1b46d7Szhanghch05 inline void 4608d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4615cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4625cb1dd27SAsmitha Karunanithi { 463fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 464fdd26906SClaire Weinan if (entriesPath.empty()) 4655cb1dd27SAsmitha Karunanithi { 4665cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4675cb1dd27SAsmitha Karunanithi return; 4685cb1dd27SAsmitha Karunanithi } 4695cb1dd27SAsmitha Karunanithi 4705eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4715eb468daSGeorge Liu dbus::utility::getManagedObjects( 4725eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 473fdd26906SClaire Weinan [asyncResp, entriesPath, 4745e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 4755eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 4765cb1dd27SAsmitha Karunanithi if (ec) 4775cb1dd27SAsmitha Karunanithi { 4785cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4795cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4805cb1dd27SAsmitha Karunanithi return; 4815cb1dd27SAsmitha Karunanithi } 4825cb1dd27SAsmitha Karunanithi 483fdd26906SClaire Weinan // Remove ending slash 484fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 485fdd26906SClaire Weinan if (!odataIdStr.empty()) 486fdd26906SClaire Weinan { 487fdd26906SClaire Weinan odataIdStr.pop_back(); 488fdd26906SClaire Weinan } 489fdd26906SClaire Weinan 490fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 491fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 492fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 493fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 49489492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 49589492a15SPatrick Williams " Dump Entries"; 496fdd26906SClaire Weinan 4975cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4985cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 499b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 500b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 501002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 5025cb1dd27SAsmitha Karunanithi 5035eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 504002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 505002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 506002d39b4SEd Tanous r.first.filename()); 507565dfb6fSClaire Weinan }); 508565dfb6fSClaire Weinan 5095cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5105cb1dd27SAsmitha Karunanithi { 511b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5125cb1dd27SAsmitha Karunanithi { 5135cb1dd27SAsmitha Karunanithi continue; 5145cb1dd27SAsmitha Karunanithi } 515c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5165cb1dd27SAsmitha Karunanithi uint64_t size = 0; 51735440d18SAsmitha Karunanithi std::string dumpStatus; 51868dd075aSAsmitha Karunanithi std::string originatorId; 51968dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 52068dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 521433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5222dfd18efSEd Tanous 5232dfd18efSEd Tanous std::string entryID = object.first.filename(); 5242dfd18efSEd Tanous if (entryID.empty()) 5255cb1dd27SAsmitha Karunanithi { 5265cb1dd27SAsmitha Karunanithi continue; 5275cb1dd27SAsmitha Karunanithi } 5285cb1dd27SAsmitha Karunanithi 529c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 53068dd075aSAsmitha Karunanithi originatorId, originatorType, 531aefe3786SClaire Weinan asyncResp); 5325cb1dd27SAsmitha Karunanithi 5330fda0f12SGeorge Liu if (dumpStatus != 5340fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 53535440d18SAsmitha Karunanithi !dumpStatus.empty()) 53635440d18SAsmitha Karunanithi { 53735440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 53835440d18SAsmitha Karunanithi continue; 53935440d18SAsmitha Karunanithi } 54035440d18SAsmitha Karunanithi 54168dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 542fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5435cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5445cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5455cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 546bbd80db8SClaire Weinan thisEntry["Created"] = 547bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5485cb1dd27SAsmitha Karunanithi 54968dd075aSAsmitha Karunanithi if (!originatorId.empty()) 55068dd075aSAsmitha Karunanithi { 55168dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 55268dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 55368dd075aSAsmitha Karunanithi } 55468dd075aSAsmitha Karunanithi 5555cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5565cb1dd27SAsmitha Karunanithi { 557d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 55889492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 55989492a15SPatrick Williams "/attachment"; 560fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5615cb1dd27SAsmitha Karunanithi } 5625cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5635cb1dd27SAsmitha Karunanithi { 564d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 565d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 56689492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 56789492a15SPatrick Williams "/attachment"; 568fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5695cb1dd27SAsmitha Karunanithi } 570b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 5715cb1dd27SAsmitha Karunanithi } 572002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5735eb468daSGeorge Liu }); 5745cb1dd27SAsmitha Karunanithi } 5755cb1dd27SAsmitha Karunanithi 5768d1b46d7Szhanghch05 inline void 577c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5788d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5795cb1dd27SAsmitha Karunanithi { 580fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 581fdd26906SClaire Weinan if (entriesPath.empty()) 5825cb1dd27SAsmitha Karunanithi { 5835cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5845cb1dd27SAsmitha Karunanithi return; 5855cb1dd27SAsmitha Karunanithi } 5865cb1dd27SAsmitha Karunanithi 5875eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5885eb468daSGeorge Liu dbus::utility::getManagedObjects( 5895eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 590fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 5915e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 59202cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5935cb1dd27SAsmitha Karunanithi if (ec) 5945cb1dd27SAsmitha Karunanithi { 5955cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5965cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5975cb1dd27SAsmitha Karunanithi return; 5985cb1dd27SAsmitha Karunanithi } 5995cb1dd27SAsmitha Karunanithi 600b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 601b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 602b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 603002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 604b47452b2SAsmitha Karunanithi 6059eb808c1SEd Tanous for (const auto& objectPath : resp) 6065cb1dd27SAsmitha Karunanithi { 607b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6085cb1dd27SAsmitha Karunanithi { 6095cb1dd27SAsmitha Karunanithi continue; 6105cb1dd27SAsmitha Karunanithi } 6115cb1dd27SAsmitha Karunanithi 6125cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 613c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6145cb1dd27SAsmitha Karunanithi uint64_t size = 0; 61535440d18SAsmitha Karunanithi std::string dumpStatus; 61668dd075aSAsmitha Karunanithi std::string originatorId; 61768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 61868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6195cb1dd27SAsmitha Karunanithi 620aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 62168dd075aSAsmitha Karunanithi timestampUs, originatorId, 62268dd075aSAsmitha Karunanithi originatorType, asyncResp); 6235cb1dd27SAsmitha Karunanithi 6240fda0f12SGeorge Liu if (dumpStatus != 6250fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 62635440d18SAsmitha Karunanithi !dumpStatus.empty()) 62735440d18SAsmitha Karunanithi { 62835440d18SAsmitha Karunanithi // Dump status is not Complete 62935440d18SAsmitha Karunanithi // return not found until status is changed to Completed 630d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 631d1bde9e5SKrzysztof Grobelny entryID); 63235440d18SAsmitha Karunanithi return; 63335440d18SAsmitha Karunanithi } 63435440d18SAsmitha Karunanithi 6355cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 63668dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 637fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6385cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6395cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6405cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 641bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 642bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6435cb1dd27SAsmitha Karunanithi 64468dd075aSAsmitha Karunanithi if (!originatorId.empty()) 64568dd075aSAsmitha Karunanithi { 64668dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 64768dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 64868dd075aSAsmitha Karunanithi } 64968dd075aSAsmitha Karunanithi 6505cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6515cb1dd27SAsmitha Karunanithi { 652d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 653d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 654fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 655fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6565cb1dd27SAsmitha Karunanithi } 6575cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6585cb1dd27SAsmitha Karunanithi { 659d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 660002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 661d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 662fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 663fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6645cb1dd27SAsmitha Karunanithi } 6655cb1dd27SAsmitha Karunanithi } 666e05aec50SEd Tanous if (!foundDumpEntry) 667b47452b2SAsmitha Karunanithi { 668b90d14f2SMyung Bae BMCWEB_LOG_WARNING << "Can't find Dump Entry " << entryID; 669b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 670b90d14f2SMyung Bae entryID); 671b47452b2SAsmitha Karunanithi return; 672b47452b2SAsmitha Karunanithi } 6735eb468daSGeorge Liu }); 6745cb1dd27SAsmitha Karunanithi } 6755cb1dd27SAsmitha Karunanithi 6768d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6779878256fSStanley Chu const std::string& entryID, 678b47452b2SAsmitha Karunanithi const std::string& dumpType) 6795cb1dd27SAsmitha Karunanithi { 680002d39b4SEd Tanous auto respHandler = 6815e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 6825cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6835cb1dd27SAsmitha Karunanithi if (ec) 6845cb1dd27SAsmitha Karunanithi { 6853de8d8baSGeorge Liu if (ec.value() == EBADR) 6863de8d8baSGeorge Liu { 6873de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6883de8d8baSGeorge Liu return; 6893de8d8baSGeorge Liu } 6905cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 691fdd26906SClaire Weinan << ec << " entryID=" << 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 7048e31778eSAsmitha Karunanithi inline DumpCreationProgress 7058e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 706a43be80fSAsmitha Karunanithi { 7078e31778eSAsmitha Karunanithi if (status == 7088e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 7098e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 7108e31778eSAsmitha Karunanithi { 7118e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7128e31778eSAsmitha Karunanithi } 7138e31778eSAsmitha Karunanithi if (status == 7148e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 7158e31778eSAsmitha Karunanithi { 7168e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 7178e31778eSAsmitha Karunanithi } 7188e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7198e31778eSAsmitha Karunanithi } 7208e31778eSAsmitha Karunanithi 7218e31778eSAsmitha Karunanithi inline DumpCreationProgress 7228e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 7238e31778eSAsmitha Karunanithi { 7248e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 7258e31778eSAsmitha Karunanithi { 7268e31778eSAsmitha Karunanithi if (key == "Status") 7278e31778eSAsmitha Karunanithi { 7288e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 7298e31778eSAsmitha Karunanithi if (value == nullptr) 7308e31778eSAsmitha Karunanithi { 7318e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 7328e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7338e31778eSAsmitha Karunanithi } 7348e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 7358e31778eSAsmitha Karunanithi } 7368e31778eSAsmitha Karunanithi } 7378e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7388e31778eSAsmitha Karunanithi } 7398e31778eSAsmitha Karunanithi 7408e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7418e31778eSAsmitha Karunanithi { 7428e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7438e31778eSAsmitha Karunanithi { 7448e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 7458e31778eSAsmitha Karunanithi } 7468e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7478e31778eSAsmitha Karunanithi { 7488e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 7498e31778eSAsmitha Karunanithi } 7508e31778eSAsmitha Karunanithi return ""; 7518e31778eSAsmitha Karunanithi } 7528e31778eSAsmitha Karunanithi 7538e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7548e31778eSAsmitha Karunanithi task::Payload&& payload, 7558e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7568e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7578e31778eSAsmitha Karunanithi { 7588e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7598e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7608e31778eSAsmitha Karunanithi 7618e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7628e31778eSAsmitha Karunanithi 7638e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7648e31778eSAsmitha Karunanithi { 7658e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 7668e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7678e31778eSAsmitha Karunanithi return; 7688e31778eSAsmitha Karunanithi } 7698e31778eSAsmitha Karunanithi 7708e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7718e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 7728e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 7735e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 7748e31778eSAsmitha Karunanithi const std::string& introspectXml) { 7758e31778eSAsmitha Karunanithi if (ec) 7768e31778eSAsmitha Karunanithi { 7778e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 7788e31778eSAsmitha Karunanithi << ec.message(); 7798e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7808e31778eSAsmitha Karunanithi return; 7818e31778eSAsmitha Karunanithi } 7828e31778eSAsmitha Karunanithi 7838e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 7848e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 7858e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 7868e31778eSAsmitha Karunanithi // Else, return task completed. 7878e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 7888e31778eSAsmitha Karunanithi 7898e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 7908e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 7918e31778eSAsmitha Karunanithi if (pRoot == nullptr) 7928e31778eSAsmitha Karunanithi { 7938e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 7948e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7958e31778eSAsmitha Karunanithi return; 7968e31778eSAsmitha Karunanithi } 7978e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 7988e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 7998e31778eSAsmitha Karunanithi 8008e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 8018e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 8028e31778eSAsmitha Karunanithi { 8038e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 8048e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 8058e31778eSAsmitha Karunanithi { 8068e31778eSAsmitha Karunanithi if (thisInterfaceName == 8078e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 8088e31778eSAsmitha Karunanithi { 8098e31778eSAsmitha Karunanithi interfaceNode = 8108e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 8118e31778eSAsmitha Karunanithi continue; 8128e31778eSAsmitha Karunanithi } 8138e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 8148e31778eSAsmitha Karunanithi break; 8158e31778eSAsmitha Karunanithi } 8168e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 8178e31778eSAsmitha Karunanithi } 8188e31778eSAsmitha Karunanithi 819a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 8208e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 8215e7e2dc5SEd Tanous const boost::system::error_code& err, sdbusplus::message_t& msg, 822a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 823cb13a392SEd Tanous if (err) 824cb13a392SEd Tanous { 8258e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8268e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8278e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 8286145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 8296145ed6fSAsmitha Karunanithi return task::completed; 830cb13a392SEd Tanous } 831b9d36b47SEd Tanous 8328e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 833a43be80fSAsmitha Karunanithi { 8348e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8358e31778eSAsmitha Karunanithi std::string prop; 8368e31778eSAsmitha Karunanithi msg.read(prop, values); 8378e31778eSAsmitha Karunanithi 8388e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8398e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8408e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8418e31778eSAsmitha Karunanithi { 8428e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8438e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8448e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8458e31778eSAsmitha Karunanithi return task::completed; 8468e31778eSAsmitha Karunanithi } 8478e31778eSAsmitha Karunanithi 8488e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8498e31778eSAsmitha Karunanithi { 8508e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8518e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 8528e31778eSAsmitha Karunanithi return !task::completed; 8538e31778eSAsmitha Karunanithi } 8548e31778eSAsmitha Karunanithi } 8558e31778eSAsmitha Karunanithi 856a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 857a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 858a43be80fSAsmitha Karunanithi 859c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 860c51a58eeSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId); 861c51a58eeSEd Tanous 862c51a58eeSEd Tanous std::string headerLoc = "Location: "; 863c51a58eeSEd Tanous headerLoc += url.buffer(); 864c51a58eeSEd Tanous 865002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 866a43be80fSAsmitha Karunanithi 8678e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8688e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 869a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 870b47452b2SAsmitha Karunanithi return task::completed; 871a43be80fSAsmitha Karunanithi }, 8728e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 8738e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 8748e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 875a43be80fSAsmitha Karunanithi 8768e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 8778e31778eSAsmitha Karunanithi // requested dump will be collected. 8788e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 879a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 8808e31778eSAsmitha Karunanithi task->payload.emplace(payload); 8818e31778eSAsmitha Karunanithi }, 8828e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 8838e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 884a43be80fSAsmitha Karunanithi } 885a43be80fSAsmitha Karunanithi 8868d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8878d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 888a43be80fSAsmitha Karunanithi { 889fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 890fdd26906SClaire Weinan if (dumpPath.empty()) 891a43be80fSAsmitha Karunanithi { 892a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 893a43be80fSAsmitha Karunanithi return; 894a43be80fSAsmitha Karunanithi } 895a43be80fSAsmitha Karunanithi 896a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 897a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 898a43be80fSAsmitha Karunanithi 89915ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 900a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 901a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 902a43be80fSAsmitha Karunanithi { 903a43be80fSAsmitha Karunanithi return; 904a43be80fSAsmitha Karunanithi } 905a43be80fSAsmitha Karunanithi 906a43be80fSAsmitha Karunanithi if (dumpType == "System") 907a43be80fSAsmitha Karunanithi { 908a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 909a43be80fSAsmitha Karunanithi { 9104978b63fSJason M. Bills BMCWEB_LOG_ERROR 9114978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 912a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 913a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 914a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 915a43be80fSAsmitha Karunanithi return; 916a43be80fSAsmitha Karunanithi } 9173174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 918a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 919a43be80fSAsmitha Karunanithi { 920a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 921ace85d60SEd Tanous messages::internalError(asyncResp->res); 922a43be80fSAsmitha Karunanithi return; 923a43be80fSAsmitha Karunanithi } 9245907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 925a43be80fSAsmitha Karunanithi } 926a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 927a43be80fSAsmitha Karunanithi { 928a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 929a43be80fSAsmitha Karunanithi { 9300fda0f12SGeorge Liu BMCWEB_LOG_ERROR 9310fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 932a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 933a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 934a43be80fSAsmitha Karunanithi return; 935a43be80fSAsmitha Karunanithi } 9363174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 937a43be80fSAsmitha Karunanithi { 938a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 939a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 940ace85d60SEd Tanous messages::internalError(asyncResp->res); 941a43be80fSAsmitha Karunanithi return; 942a43be80fSAsmitha Karunanithi } 9435907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 9445907571dSAsmitha Karunanithi } 9455907571dSAsmitha Karunanithi else 9465907571dSAsmitha Karunanithi { 9475907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 9485907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9495907571dSAsmitha Karunanithi return; 950a43be80fSAsmitha Karunanithi } 951a43be80fSAsmitha Karunanithi 9528e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9538e31778eSAsmitha Karunanithi createDumpParamVec; 9548e31778eSAsmitha Karunanithi 955f574a8e1SCarson Labrado if (req.session != nullptr) 956f574a8e1SCarson Labrado { 95768dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 95868dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 95968dd075aSAsmitha Karunanithi req.session->clientIp); 96068dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 96168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 96268dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 963f574a8e1SCarson Labrado } 96468dd075aSAsmitha Karunanithi 965a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9665e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 9675e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 9685e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 9698e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 970a43be80fSAsmitha Karunanithi if (ec) 971a43be80fSAsmitha Karunanithi { 972a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9735907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9745907571dSAsmitha Karunanithi if (dbusError == nullptr) 9755907571dSAsmitha Karunanithi { 9765907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9775907571dSAsmitha Karunanithi return; 9785907571dSAsmitha Karunanithi } 9795907571dSAsmitha Karunanithi 9805907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9815907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9825907571dSAsmitha Karunanithi if (std::string_view( 9835907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9845907571dSAsmitha Karunanithi dbusError->name) 9855907571dSAsmitha Karunanithi { 9865907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9875907571dSAsmitha Karunanithi return; 9885907571dSAsmitha Karunanithi } 9895907571dSAsmitha Karunanithi if (std::string_view( 9905907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9915907571dSAsmitha Karunanithi dbusError->name) 9925907571dSAsmitha Karunanithi { 9935907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9945907571dSAsmitha Karunanithi return; 9955907571dSAsmitha Karunanithi } 9965907571dSAsmitha Karunanithi if (std::string_view( 9975907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9985907571dSAsmitha Karunanithi dbusError->name) 9995907571dSAsmitha Karunanithi { 10005907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 10015907571dSAsmitha Karunanithi return; 10025907571dSAsmitha Karunanithi } 10035907571dSAsmitha Karunanithi // Other Dbus errors such as: 10045907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 10055907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 10065907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 10075907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 10085907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 10095907571dSAsmitha Karunanithi // back to the client. 1010a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1011a43be80fSAsmitha Karunanithi return; 1012a43be80fSAsmitha Karunanithi } 10138e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 10148e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1015a43be80fSAsmitha Karunanithi }, 1016b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 1017b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 1018b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 10198e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1020a43be80fSAsmitha Karunanithi } 1021a43be80fSAsmitha Karunanithi 10228d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10238d1b46d7Szhanghch05 const std::string& dumpType) 102480319af1SAsmitha Karunanithi { 1025b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 1026b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 10278d1b46d7Szhanghch05 10280d946211SClaire Weinan crow::connections::systemBus->async_method_call( 10290d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 103080319af1SAsmitha Karunanithi if (ec) 103180319af1SAsmitha Karunanithi { 10320d946211SClaire Weinan BMCWEB_LOG_ERROR << "clearDump resp_handler got error " << ec; 103380319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 103480319af1SAsmitha Karunanithi return; 103580319af1SAsmitha Karunanithi } 10360d946211SClaire Weinan }, 10370d946211SClaire Weinan "xyz.openbmc_project.Dump.Manager", 10380d946211SClaire Weinan "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 10390d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 104080319af1SAsmitha Karunanithi } 104180319af1SAsmitha Karunanithi 1042b9d36b47SEd Tanous inline static void 1043b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1044b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1045b9d36b47SEd Tanous std::string& logfile) 1046043a0536SJohnathan Mantey { 1047d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1048d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1049d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1050d1bde9e5SKrzysztof Grobelny 1051d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1052d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1053d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1054d1bde9e5SKrzysztof Grobelny 1055d1bde9e5SKrzysztof Grobelny if (!success) 1056043a0536SJohnathan Mantey { 1057d1bde9e5SKrzysztof Grobelny return; 1058043a0536SJohnathan Mantey } 1059d1bde9e5SKrzysztof Grobelny 1060d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1061043a0536SJohnathan Mantey { 1062d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1063d1bde9e5SKrzysztof Grobelny } 1064d1bde9e5SKrzysztof Grobelny 1065d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1066043a0536SJohnathan Mantey { 1067d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1068043a0536SJohnathan Mantey } 1069d1bde9e5SKrzysztof Grobelny 1070d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1071043a0536SJohnathan Mantey { 1072d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1073043a0536SJohnathan Mantey } 1074043a0536SJohnathan Mantey } 1075043a0536SJohnathan Mantey 10767e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10771da66f75SEd Tanous { 1078c4bf6374SJason M. Bills /** 1079c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1080c4bf6374SJason M. Bills */ 108122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1082ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1083002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1084002d39b4SEd Tanous [&app](const crow::Request& req, 108522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 108622d268cbSEd Tanous const std::string& systemName) { 10873ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1088c4bf6374SJason M. Bills { 108945ca1b86SEd Tanous return; 109045ca1b86SEd Tanous } 109122d268cbSEd Tanous if (systemName != "system") 109222d268cbSEd Tanous { 109322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 109422d268cbSEd Tanous systemName); 109522d268cbSEd Tanous return; 109622d268cbSEd Tanous } 109722d268cbSEd Tanous 10987e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10997e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1100c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1101c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1102c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1103029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 110445ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1105c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1106c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1107002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1108c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11091476687dSEd Tanous nlohmann::json::object_t eventLog; 11101476687dSEd Tanous eventLog["@odata.id"] = 11111476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1112b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 11135cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 11141476687dSEd Tanous nlohmann::json::object_t dumpLog; 1115002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1116b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1117c9bb6861Sraviteja-b #endif 1118c9bb6861Sraviteja-b 1119d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 11201476687dSEd Tanous nlohmann::json::object_t crashdump; 11211476687dSEd Tanous crashdump["@odata.id"] = 11221476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1123b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1124d53dd41fSJason M. Bills #endif 1125b7028ebfSSpencer Ku 1126b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 11271476687dSEd Tanous nlohmann::json::object_t hostlogger; 11281476687dSEd Tanous hostlogger["@odata.id"] = 11291476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1130b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1131b7028ebfSSpencer Ku #endif 1132c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1133c4bf6374SJason M. Bills logServiceArray.size(); 1134a3316fc6SZhikuiRen 11357a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11367a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11377a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11387a1dbc48SGeorge Liu "/", 0, interfaces, 11397a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1140b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1141b9d36b47SEd Tanous subtreePath) { 1142a3316fc6SZhikuiRen if (ec) 1143a3316fc6SZhikuiRen { 1144a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 1145a3316fc6SZhikuiRen return; 1146a3316fc6SZhikuiRen } 1147a3316fc6SZhikuiRen 114855f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1149a3316fc6SZhikuiRen { 1150a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1151a3316fc6SZhikuiRen { 115223a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1153a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1154613dabeaSEd Tanous nlohmann::json::object_t member; 1155613dabeaSEd Tanous member["@odata.id"] = 1156613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1157613dabeaSEd Tanous 1158b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1159613dabeaSEd Tanous 116045ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 116123a21a1cSEd Tanous logServiceArrayLocal.size(); 1162a3316fc6SZhikuiRen return; 1163a3316fc6SZhikuiRen } 1164a3316fc6SZhikuiRen } 11657a1dbc48SGeorge Liu }); 11667e860f15SJohn Edward Broadbent }); 1167c4bf6374SJason M. Bills } 1168c4bf6374SJason M. Bills 11697e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1170c4bf6374SJason M. Bills { 117122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1172ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1173002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1174002d39b4SEd Tanous [&app](const crow::Request& req, 117522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 117622d268cbSEd Tanous const std::string& systemName) { 11773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117845ca1b86SEd Tanous { 117945ca1b86SEd Tanous return; 118045ca1b86SEd Tanous } 118122d268cbSEd Tanous if (systemName != "system") 118222d268cbSEd Tanous { 118322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 118422d268cbSEd Tanous systemName); 118522d268cbSEd Tanous return; 118622d268cbSEd Tanous } 1187c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1188029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1189c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1190c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1191c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1192002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1193c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1194c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11957c8c4058STejas Patil 11967c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11972b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11987c8c4058STejas Patil 11997c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 12007c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 12017c8c4058STejas Patil redfishDateTimeOffset.second; 12027c8c4058STejas Patil 12031476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 12041476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1205e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1206e7d6c8b2SGunnar Mills 12070fda0f12SGeorge Liu {"target", 12080fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 12097e860f15SJohn Edward Broadbent }); 1210489640c6SJason M. Bills } 1211489640c6SJason M. Bills 12127e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1213489640c6SJason M. Bills { 12144978b63fSJason M. Bills BMCWEB_ROUTE( 12154978b63fSJason M. Bills app, 121622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1217432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 12187e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 121945ca1b86SEd Tanous [&app](const crow::Request& req, 122022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 122122d268cbSEd Tanous const std::string& systemName) { 12223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 122345ca1b86SEd Tanous { 122445ca1b86SEd Tanous return; 122545ca1b86SEd Tanous } 122622d268cbSEd Tanous if (systemName != "system") 122722d268cbSEd Tanous { 122822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 122922d268cbSEd Tanous systemName); 123022d268cbSEd Tanous return; 123122d268cbSEd Tanous } 1232489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1233489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1234489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1235489640c6SJason M. Bills { 1236489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1237489640c6SJason M. Bills { 1238489640c6SJason M. Bills std::error_code ec; 1239489640c6SJason M. Bills std::filesystem::remove(file, ec); 1240489640c6SJason M. Bills } 1241489640c6SJason M. Bills } 1242489640c6SJason M. Bills 1243489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1244489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 12455e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1246489640c6SJason M. Bills if (ec) 1247489640c6SJason M. Bills { 1248002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1249489640c6SJason M. Bills messages::internalError(asyncResp->res); 1250489640c6SJason M. Bills return; 1251489640c6SJason M. Bills } 1252489640c6SJason M. Bills 1253489640c6SJason M. Bills messages::success(asyncResp->res); 1254489640c6SJason M. Bills }, 1255489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1256002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1257002d39b4SEd Tanous "replace"); 12587e860f15SJohn Edward Broadbent }); 1259c4bf6374SJason M. Bills } 1260c4bf6374SJason M. Bills 1261ac992cdeSJason M. Bills enum class LogParseError 1262ac992cdeSJason M. Bills { 1263ac992cdeSJason M. Bills success, 1264ac992cdeSJason M. Bills parseFailed, 1265ac992cdeSJason M. Bills messageIdNotInRegistry, 1266ac992cdeSJason M. Bills }; 1267ac992cdeSJason M. Bills 1268ac992cdeSJason M. Bills static LogParseError 1269ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1270b5a76932SEd Tanous const std::string& logEntry, 1271de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1272c4bf6374SJason M. Bills { 127395820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1274cd225da8SJason M. Bills // First get the Timestamp 1275f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1276cd225da8SJason M. Bills if (space == std::string::npos) 127795820184SJason M. Bills { 1278ac992cdeSJason M. Bills return LogParseError::parseFailed; 127995820184SJason M. Bills } 1280cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1281cd225da8SJason M. Bills // Then get the log contents 1282f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1283cd225da8SJason M. Bills if (entryStart == std::string::npos) 1284cd225da8SJason M. Bills { 1285ac992cdeSJason M. Bills return LogParseError::parseFailed; 1286cd225da8SJason M. Bills } 1287cd225da8SJason M. Bills std::string_view entry(logEntry); 1288cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1289cd225da8SJason M. Bills // Use split to separate the entry into its fields 1290cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 129150ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1292cd225da8SJason M. Bills // We need at least a MessageId to be valid 1293*1e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 1294*1e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1295cd225da8SJason M. Bills { 1296ac992cdeSJason M. Bills return LogParseError::parseFailed; 1297cd225da8SJason M. Bills } 1298*1e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 12994851d45dSJason M. Bills // Get the Message from the MessageRegistry 1300fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1301c4bf6374SJason M. Bills 1302*1e6deaf6SEd Tanous logEntryIter++; 130354417b02SSui Chen if (message == nullptr) 1304c4bf6374SJason M. Bills { 130554417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1306ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1307c4bf6374SJason M. Bills } 1308c4bf6374SJason M. Bills 1309*1e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 1310*1e6deaf6SEd Tanous logEntryFields.end()); 1311*1e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 1312*1e6deaf6SEd Tanous message->message); 1313*1e6deaf6SEd Tanous if (msg.empty()) 131415a86ff6SJason M. Bills { 1315*1e6deaf6SEd Tanous return LogParseError::parseFailed; 131615a86ff6SJason M. Bills } 13174851d45dSJason M. Bills 131895820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 131995820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 132095820184SJason M. Bills // between the '.' and the '+', so just remove them. 1321f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1322f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 132395820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1324c4bf6374SJason M. Bills { 132595820184SJason M. Bills timestamp.erase(dot, plus - dot); 1326c4bf6374SJason M. Bills } 1327c4bf6374SJason M. Bills 1328c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13299c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1330ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1331ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1332ef4c65b7SEd Tanous logEntryID); 133384afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 133484afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 133584afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 133684afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 133784afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 133884afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 133984afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 134084afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1341ac992cdeSJason M. Bills return LogParseError::success; 1342c4bf6374SJason M. Bills } 1343c4bf6374SJason M. Bills 13447e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1345c4bf6374SJason M. Bills { 134622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13478b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1348002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1349002d39b4SEd Tanous [&app](const crow::Request& req, 135022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 135122d268cbSEd Tanous const std::string& systemName) { 1352c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1353c937d2bfSEd Tanous .canDelegateTop = true, 1354c937d2bfSEd Tanous .canDelegateSkip = true, 1355c937d2bfSEd Tanous }; 1356c937d2bfSEd Tanous query_param::Query delegatedQuery; 1357c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13583ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1359c4bf6374SJason M. Bills { 1360c4bf6374SJason M. Bills return; 1361c4bf6374SJason M. Bills } 136222d268cbSEd Tanous if (systemName != "system") 136322d268cbSEd Tanous { 136422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 136522d268cbSEd Tanous systemName); 136622d268cbSEd Tanous return; 136722d268cbSEd Tanous } 136822d268cbSEd Tanous 13695143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13703648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13713648c8beSEd Tanous 13727e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13737e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1374c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1375c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1376c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1377029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1378c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1379c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1380c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1381cb92c03bSAndrew Geissler 13824978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1383c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13847e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13857e860f15SJohn Edward Broadbent // entry 138695820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 138795820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1388b01bf299SEd Tanous uint64_t entryCount = 0; 1389cd225da8SJason M. Bills std::string logEntry; 139095820184SJason M. Bills 13917e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13927e860f15SJohn Edward Broadbent // backwards 1393002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1394002d39b4SEd Tanous it++) 1395c4bf6374SJason M. Bills { 1396cd225da8SJason M. Bills std::ifstream logStream(*it); 139795820184SJason M. Bills if (!logStream.is_open()) 1398c4bf6374SJason M. Bills { 1399c4bf6374SJason M. Bills continue; 1400c4bf6374SJason M. Bills } 1401c4bf6374SJason M. Bills 1402e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1403e85d6b16SJason M. Bills bool firstEntry = true; 140495820184SJason M. Bills while (std::getline(logStream, logEntry)) 140595820184SJason M. Bills { 1406c4bf6374SJason M. Bills std::string idStr; 1407e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1408c4bf6374SJason M. Bills { 1409c4bf6374SJason M. Bills continue; 1410c4bf6374SJason M. Bills } 1411e85d6b16SJason M. Bills firstEntry = false; 1412e85d6b16SJason M. Bills 1413de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 141489492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 141589492a15SPatrick Williams bmcLogEntry); 1416ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1417ac992cdeSJason M. Bills { 1418ac992cdeSJason M. Bills continue; 1419ac992cdeSJason M. Bills } 1420ac992cdeSJason M. Bills if (status != LogParseError::success) 1421c4bf6374SJason M. Bills { 1422c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1423c4bf6374SJason M. Bills return; 1424c4bf6374SJason M. Bills } 1425de703c5dSJason M. Bills 1426de703c5dSJason M. Bills entryCount++; 1427de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1428de703c5dSJason M. Bills // start) and top (number of entries to display) 14293648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1430de703c5dSJason M. Bills { 1431de703c5dSJason M. Bills continue; 1432de703c5dSJason M. Bills } 1433de703c5dSJason M. Bills 1434b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1435c4bf6374SJason M. Bills } 143695820184SJason M. Bills } 1437c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14383648c8beSEd Tanous if (skip + top < entryCount) 1439c4bf6374SJason M. Bills { 1440c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14414978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14423648c8beSEd Tanous std::to_string(skip + top); 1443c4bf6374SJason M. Bills } 14447e860f15SJohn Edward Broadbent }); 1445897967deSJason M. Bills } 1446897967deSJason M. Bills 14477e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1448897967deSJason M. Bills { 14497e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 145022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1451ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14527e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 145345ca1b86SEd Tanous [&app](const crow::Request& req, 14547e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 145522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 145745ca1b86SEd Tanous { 145845ca1b86SEd Tanous return; 145945ca1b86SEd Tanous } 146022d268cbSEd Tanous 146122d268cbSEd Tanous if (systemName != "system") 146222d268cbSEd Tanous { 146322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 146422d268cbSEd Tanous systemName); 146522d268cbSEd Tanous return; 146622d268cbSEd Tanous } 146722d268cbSEd Tanous 14687e860f15SJohn Edward Broadbent const std::string& targetID = param; 14698d1b46d7Szhanghch05 14707e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14717e860f15SJohn Edward Broadbent // entry to find the target entry 1472897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1473897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1474897967deSJason M. Bills std::string logEntry; 1475897967deSJason M. Bills 14767e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14777e860f15SJohn Edward Broadbent // backwards 1478002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1479002d39b4SEd Tanous it++) 1480897967deSJason M. Bills { 1481897967deSJason M. Bills std::ifstream logStream(*it); 1482897967deSJason M. Bills if (!logStream.is_open()) 1483897967deSJason M. Bills { 1484897967deSJason M. Bills continue; 1485897967deSJason M. Bills } 1486897967deSJason M. Bills 1487897967deSJason M. Bills // Reset the unique ID on the first entry 1488897967deSJason M. Bills bool firstEntry = true; 1489897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1490897967deSJason M. Bills { 1491897967deSJason M. Bills std::string idStr; 1492897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1493897967deSJason M. Bills { 1494897967deSJason M. Bills continue; 1495897967deSJason M. Bills } 1496897967deSJason M. Bills firstEntry = false; 1497897967deSJason M. Bills 1498897967deSJason M. Bills if (idStr == targetID) 1499897967deSJason M. Bills { 1500de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1501ac992cdeSJason M. Bills LogParseError status = 1502ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1503ac992cdeSJason M. Bills if (status != LogParseError::success) 1504897967deSJason M. Bills { 1505897967deSJason M. Bills messages::internalError(asyncResp->res); 1506897967deSJason M. Bills return; 1507897967deSJason M. Bills } 1508d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1509897967deSJason M. Bills return; 1510897967deSJason M. Bills } 1511897967deSJason M. Bills } 1512897967deSJason M. Bills } 1513897967deSJason M. Bills // Requested ID was not found 15149db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15157e860f15SJohn Edward Broadbent }); 151608a4e4b5SAnthony Wilson } 151708a4e4b5SAnthony Wilson 15187e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 151908a4e4b5SAnthony Wilson { 152022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1521ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1522002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1523002d39b4SEd Tanous [&app](const crow::Request& req, 152422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 152522d268cbSEd Tanous const std::string& systemName) { 15263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 152745ca1b86SEd Tanous { 152845ca1b86SEd Tanous return; 152945ca1b86SEd Tanous } 153022d268cbSEd Tanous if (systemName != "system") 153122d268cbSEd Tanous { 153222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 153322d268cbSEd Tanous systemName); 153422d268cbSEd Tanous return; 153522d268cbSEd Tanous } 153622d268cbSEd Tanous 15377e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15387e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 153908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 154008a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 154108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 154208a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 154308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 154408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 154508a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 154608a4e4b5SAnthony Wilson 1547cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1548cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 15495eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 15505eb468daSGeorge Liu dbus::utility::getManagedObjects( 15515eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 15525e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1553914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1554cb92c03bSAndrew Geissler if (ec) 1555cb92c03bSAndrew Geissler { 1556cb92c03bSAndrew Geissler // TODO Handle for specific error code 1557cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1558002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1559cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1560cb92c03bSAndrew Geissler return; 1561cb92c03bSAndrew Geissler } 1562002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1563cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15649eb808c1SEd Tanous for (const auto& objectPath : resp) 1565cb92c03bSAndrew Geissler { 1566914e2d5dSEd Tanous const uint32_t* id = nullptr; 1567c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1568c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1569914e2d5dSEd Tanous const std::string* severity = nullptr; 1570914e2d5dSEd Tanous const std::string* message = nullptr; 1571914e2d5dSEd Tanous const std::string* filePath = nullptr; 15729c11a172SVijay Lobo const std::string* resolution = nullptr; 157375710de2SXiaochao Ma bool resolved = false; 15749017faf2SAbhishek Patel const std::string* notify = nullptr; 15759017faf2SAbhishek Patel 15769eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1577f86bb901SAdriana Kobylak { 1578f86bb901SAdriana Kobylak if (interfaceMap.first == 1579f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1580f86bb901SAdriana Kobylak { 1581002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1582cb92c03bSAndrew Geissler { 1583cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1584cb92c03bSAndrew Geissler { 1585002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1586cb92c03bSAndrew Geissler } 1587cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1588cb92c03bSAndrew Geissler { 1589002d39b4SEd Tanous timestamp = 1590002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15917e860f15SJohn Edward Broadbent } 1592002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 15937e860f15SJohn Edward Broadbent { 1594002d39b4SEd Tanous updateTimestamp = 1595002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15967e860f15SJohn Edward Broadbent } 15977e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 15987e860f15SJohn Edward Broadbent { 15997e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 16007e860f15SJohn Edward Broadbent &propertyMap.second); 16017e860f15SJohn Edward Broadbent } 16029c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 16039c11a172SVijay Lobo { 16049c11a172SVijay Lobo resolution = std::get_if<std::string>( 16059c11a172SVijay Lobo &propertyMap.second); 16069c11a172SVijay Lobo } 16077e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 16087e860f15SJohn Edward Broadbent { 16097e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 16107e860f15SJohn Edward Broadbent &propertyMap.second); 16117e860f15SJohn Edward Broadbent } 16127e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 16137e860f15SJohn Edward Broadbent { 1614914e2d5dSEd Tanous const bool* resolveptr = 1615002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16167e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16177e860f15SJohn Edward Broadbent { 1618002d39b4SEd Tanous messages::internalError(asyncResp->res); 16197e860f15SJohn Edward Broadbent return; 16207e860f15SJohn Edward Broadbent } 16217e860f15SJohn Edward Broadbent resolved = *resolveptr; 16227e860f15SJohn Edward Broadbent } 16239017faf2SAbhishek Patel else if (propertyMap.first == 16249017faf2SAbhishek Patel "ServiceProviderNotify") 16259017faf2SAbhishek Patel { 16269017faf2SAbhishek Patel notify = std::get_if<std::string>( 16279017faf2SAbhishek Patel &propertyMap.second); 16289017faf2SAbhishek Patel if (notify == nullptr) 16299017faf2SAbhishek Patel { 16309017faf2SAbhishek Patel messages::internalError(asyncResp->res); 16319017faf2SAbhishek Patel return; 16329017faf2SAbhishek Patel } 16339017faf2SAbhishek Patel } 16347e860f15SJohn Edward Broadbent } 16357e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16367e860f15SJohn Edward Broadbent severity == nullptr) 16377e860f15SJohn Edward Broadbent { 16387e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16397e860f15SJohn Edward Broadbent return; 16407e860f15SJohn Edward Broadbent } 16417e860f15SJohn Edward Broadbent } 16427e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16437e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16447e860f15SJohn Edward Broadbent { 1645002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16467e860f15SJohn Edward Broadbent { 16477e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16487e860f15SJohn Edward Broadbent { 16497e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16507e860f15SJohn Edward Broadbent &propertyMap.second); 16517e860f15SJohn Edward Broadbent } 16527e860f15SJohn Edward Broadbent } 16537e860f15SJohn Edward Broadbent } 16547e860f15SJohn Edward Broadbent } 16557e860f15SJohn Edward Broadbent // Object path without the 16567e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16577e860f15SJohn Edward Broadbent // and continue. 16587e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1659c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1660c419c759SEd Tanous updateTimestamp == nullptr) 16617e860f15SJohn Edward Broadbent { 16627e860f15SJohn Edward Broadbent continue; 16637e860f15SJohn Edward Broadbent } 16647e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16657e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16669c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1667ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1668ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1669ef4c65b7SEd Tanous std::to_string(*id)); 16707e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16717e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16727e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16737e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16749c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16759c11a172SVijay Lobo { 16769c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16779c11a172SVijay Lobo } 16789017faf2SAbhishek Patel std::optional<bool> notifyAction = 16799017faf2SAbhishek Patel getProviderNotifyAction(*notify); 16809017faf2SAbhishek Patel if (notifyAction) 16819017faf2SAbhishek Patel { 16829017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 16839017faf2SAbhishek Patel } 16847e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16857e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16867e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16877e860f15SJohn Edward Broadbent thisEntry["Created"] = 16882b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 16897e860f15SJohn Edward Broadbent thisEntry["Modified"] = 16902b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 16917e860f15SJohn Edward Broadbent if (filePath != nullptr) 16927e860f15SJohn Edward Broadbent { 16937e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 16940fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16957e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 16967e860f15SJohn Edward Broadbent } 16977e860f15SJohn Edward Broadbent } 1698002d39b4SEd Tanous std::sort( 1699002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1700002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 17017e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 17027e860f15SJohn Edward Broadbent }); 17037e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 17047e860f15SJohn Edward Broadbent entriesArray.size(); 17055eb468daSGeorge Liu }); 17067e860f15SJohn Edward Broadbent }); 17077e860f15SJohn Edward Broadbent } 17087e860f15SJohn Edward Broadbent 17097e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 17107e860f15SJohn Edward Broadbent { 17117e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 171222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1713ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1714002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1715002d39b4SEd Tanous [&app](const crow::Request& req, 17167e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 171722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17183ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17197e860f15SJohn Edward Broadbent { 172045ca1b86SEd Tanous return; 172145ca1b86SEd Tanous } 172222d268cbSEd Tanous if (systemName != "system") 172322d268cbSEd Tanous { 172422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 172522d268cbSEd Tanous systemName); 172622d268cbSEd Tanous return; 172722d268cbSEd Tanous } 172822d268cbSEd Tanous 17297e860f15SJohn Edward Broadbent std::string entryID = param; 17307e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17317e860f15SJohn Edward Broadbent 17327e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17337e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1734d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1735d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1736d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 17375e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1738b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17397e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17407e860f15SJohn Edward Broadbent { 1741d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1742d1bde9e5SKrzysztof Grobelny entryID); 17437e860f15SJohn Edward Broadbent return; 17447e860f15SJohn Edward Broadbent } 17457e860f15SJohn Edward Broadbent if (ec) 17467e860f15SJohn Edward Broadbent { 17470fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1748002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17497e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17507e860f15SJohn Edward Broadbent return; 17517e860f15SJohn Edward Broadbent } 1752914e2d5dSEd Tanous const uint32_t* id = nullptr; 1753c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1754c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1755914e2d5dSEd Tanous const std::string* severity = nullptr; 1756914e2d5dSEd Tanous const std::string* message = nullptr; 1757914e2d5dSEd Tanous const std::string* filePath = nullptr; 17589c11a172SVijay Lobo const std::string* resolution = nullptr; 17597e860f15SJohn Edward Broadbent bool resolved = false; 17609017faf2SAbhishek Patel const std::string* notify = nullptr; 17617e860f15SJohn Edward Broadbent 1762d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1763d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1764d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17659c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 17669017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 17679017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1768d1bde9e5SKrzysztof Grobelny 1769d1bde9e5SKrzysztof Grobelny if (!success) 177075710de2SXiaochao Ma { 177175710de2SXiaochao Ma messages::internalError(asyncResp->res); 177275710de2SXiaochao Ma return; 177375710de2SXiaochao Ma } 1774d1bde9e5SKrzysztof Grobelny 1775002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 17769017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 17779017faf2SAbhishek Patel notify == nullptr) 1778f86bb901SAdriana Kobylak { 1779ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1780271584abSEd Tanous return; 1781271584abSEd Tanous } 17829017faf2SAbhishek Patel 1783f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17849c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1785ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1786ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1787ef4c65b7SEd Tanous std::to_string(*id)); 178845ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1789f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1790f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1791f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 17929017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 17939017faf2SAbhishek Patel if (notifyAction) 17949017faf2SAbhishek Patel { 17959017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 17969017faf2SAbhishek Patel *notifyAction; 17979017faf2SAbhishek Patel } 17989c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17999c11a172SVijay Lobo { 18009c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 18019c11a172SVijay Lobo } 1802f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1803f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1804f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1805f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 18062b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1807f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 18082b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1809f86bb901SAdriana Kobylak if (filePath != nullptr) 1810f86bb901SAdriana Kobylak { 1811f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1812e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1813e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1814f86bb901SAdriana Kobylak } 1815d1bde9e5SKrzysztof Grobelny }); 18167e860f15SJohn Edward Broadbent }); 1817336e96c6SChicago Duan 18187e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 181922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1820ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 182245ca1b86SEd Tanous [&app](const crow::Request& req, 18237e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 182422d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 18253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 182645ca1b86SEd Tanous { 182745ca1b86SEd Tanous return; 182845ca1b86SEd Tanous } 182922d268cbSEd Tanous if (systemName != "system") 183022d268cbSEd Tanous { 183122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 183222d268cbSEd Tanous systemName); 183322d268cbSEd Tanous return; 183422d268cbSEd Tanous } 183575710de2SXiaochao Ma std::optional<bool> resolved; 183675710de2SXiaochao Ma 183715ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 18387e860f15SJohn Edward Broadbent resolved)) 183975710de2SXiaochao Ma { 184075710de2SXiaochao Ma return; 184175710de2SXiaochao Ma } 184275710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 184375710de2SXiaochao Ma 184475710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 18455e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 184675710de2SXiaochao Ma if (ec) 184775710de2SXiaochao Ma { 184875710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 184975710de2SXiaochao Ma messages::internalError(asyncResp->res); 185075710de2SXiaochao Ma return; 185175710de2SXiaochao Ma } 185275710de2SXiaochao Ma }, 185375710de2SXiaochao Ma "xyz.openbmc_project.Logging", 185475710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 185575710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 185675710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1857168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18587e860f15SJohn Edward Broadbent }); 185975710de2SXiaochao Ma 18607e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 186122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1862ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1863ed398213SEd Tanous 1864002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1865002d39b4SEd Tanous [&app](const crow::Request& req, 1866002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 186722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1869336e96c6SChicago Duan { 187045ca1b86SEd Tanous return; 187145ca1b86SEd Tanous } 187222d268cbSEd Tanous if (systemName != "system") 187322d268cbSEd Tanous { 187422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 187522d268cbSEd Tanous systemName); 187622d268cbSEd Tanous return; 187722d268cbSEd Tanous } 1878336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1879336e96c6SChicago Duan 18807e860f15SJohn Edward Broadbent std::string entryID = param; 1881336e96c6SChicago Duan 1882336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1883336e96c6SChicago Duan 1884336e96c6SChicago Duan // Process response from Logging service. 1885002d39b4SEd Tanous auto respHandler = 18865e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 1887002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1888336e96c6SChicago Duan if (ec) 1889336e96c6SChicago Duan { 18903de8d8baSGeorge Liu if (ec.value() == EBADR) 18913de8d8baSGeorge Liu { 189245ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 189345ca1b86SEd Tanous entryID); 18943de8d8baSGeorge Liu return; 18953de8d8baSGeorge Liu } 1896336e96c6SChicago Duan // TODO Handle for specific error code 18970fda0f12SGeorge Liu BMCWEB_LOG_ERROR 18980fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1899336e96c6SChicago Duan << ec; 1900336e96c6SChicago Duan asyncResp->res.result( 1901336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1902336e96c6SChicago Duan return; 1903336e96c6SChicago Duan } 1904336e96c6SChicago Duan 1905336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1906336e96c6SChicago Duan }; 1907336e96c6SChicago Duan 1908336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1909336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1910336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1911336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1912336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 19137e860f15SJohn Edward Broadbent }); 1914400fd1fbSAdriana Kobylak } 1915400fd1fbSAdriana Kobylak 19167e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1917400fd1fbSAdriana Kobylak { 19180fda0f12SGeorge Liu BMCWEB_ROUTE( 19190fda0f12SGeorge Liu app, 192022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1921ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 19227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 192345ca1b86SEd Tanous [&app](const crow::Request& req, 19247e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 192522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19277e860f15SJohn Edward Broadbent { 192845ca1b86SEd Tanous return; 192945ca1b86SEd Tanous } 193072e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 193199351cd8SEd Tanous req.getHeaderValue("Accept"), 19324a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1933400fd1fbSAdriana Kobylak { 1934002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1935400fd1fbSAdriana Kobylak return; 1936400fd1fbSAdriana Kobylak } 193722d268cbSEd Tanous if (systemName != "system") 193822d268cbSEd Tanous { 193922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 194022d268cbSEd Tanous systemName); 194122d268cbSEd Tanous return; 194222d268cbSEd Tanous } 1943400fd1fbSAdriana Kobylak 19447e860f15SJohn Edward Broadbent std::string entryID = param; 1945400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1946400fd1fbSAdriana Kobylak 1947400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 19485e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1949400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1950400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1951400fd1fbSAdriana Kobylak { 1952002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1953002d39b4SEd Tanous entryID); 1954400fd1fbSAdriana Kobylak return; 1955400fd1fbSAdriana Kobylak } 1956400fd1fbSAdriana Kobylak if (ec) 1957400fd1fbSAdriana Kobylak { 1958400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1959400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1960400fd1fbSAdriana Kobylak return; 1961400fd1fbSAdriana Kobylak } 1962400fd1fbSAdriana Kobylak 1963400fd1fbSAdriana Kobylak int fd = -1; 1964400fd1fbSAdriana Kobylak fd = dup(unixfd); 1965400fd1fbSAdriana Kobylak if (fd == -1) 1966400fd1fbSAdriana Kobylak { 1967400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1968400fd1fbSAdriana Kobylak return; 1969400fd1fbSAdriana Kobylak } 1970400fd1fbSAdriana Kobylak 1971400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1972400fd1fbSAdriana Kobylak if (size == -1) 1973400fd1fbSAdriana Kobylak { 1974400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1975400fd1fbSAdriana Kobylak return; 1976400fd1fbSAdriana Kobylak } 1977400fd1fbSAdriana Kobylak 1978400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1979400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1980400fd1fbSAdriana Kobylak if (size > maxFileSize) 1981400fd1fbSAdriana Kobylak { 1982002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1983400fd1fbSAdriana Kobylak << maxFileSize; 1984400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1985400fd1fbSAdriana Kobylak return; 1986400fd1fbSAdriana Kobylak } 1987400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1988400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1989400fd1fbSAdriana Kobylak if (rc == -1) 1990400fd1fbSAdriana Kobylak { 1991400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1992400fd1fbSAdriana Kobylak return; 1993400fd1fbSAdriana Kobylak } 1994400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1995400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1996400fd1fbSAdriana Kobylak { 1997400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1998400fd1fbSAdriana Kobylak return; 1999400fd1fbSAdriana Kobylak } 2000400fd1fbSAdriana Kobylak close(fd); 2001400fd1fbSAdriana Kobylak 2002400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 2003002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 2004400fd1fbSAdriana Kobylak 2005d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 2006400fd1fbSAdriana Kobylak "application/octet-stream"); 2007d9f6c621SEd Tanous asyncResp->res.addHeader( 2008d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 2009400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 2010400fd1fbSAdriana Kobylak }, 2011400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 2012400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 2013400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 20147e860f15SJohn Edward Broadbent }); 20151da66f75SEd Tanous } 20161da66f75SEd Tanous 2017b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2018b7028ebfSSpencer Ku 2019b7028ebfSSpencer Ku inline bool 2020b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2021b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2022b7028ebfSSpencer Ku { 2023b7028ebfSSpencer Ku std::error_code ec; 2024b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2025b7028ebfSSpencer Ku if (ec) 2026b7028ebfSSpencer Ku { 2027b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 2028b7028ebfSSpencer Ku return false; 2029b7028ebfSSpencer Ku } 2030b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2031b7028ebfSSpencer Ku { 2032b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2033b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2034b7028ebfSSpencer Ku // path 203511ba3979SEd Tanous if (filename.starts_with("log")) 2036b7028ebfSSpencer Ku { 2037b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2038b7028ebfSSpencer Ku } 2039b7028ebfSSpencer Ku } 2040b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2041b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2042b7028ebfSSpencer Ku // descending order. 2043b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2044b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2045b7028ebfSSpencer Ku 2046b7028ebfSSpencer Ku return true; 2047b7028ebfSSpencer Ku } 2048b7028ebfSSpencer Ku 204902cad96eSEd Tanous inline bool getHostLoggerEntries( 205002cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 205102cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2052b7028ebfSSpencer Ku { 2053b7028ebfSSpencer Ku GzFileReader logFile; 2054b7028ebfSSpencer Ku 2055b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2056b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2057b7028ebfSSpencer Ku { 2058b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2059b7028ebfSSpencer Ku { 2060b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2061b7028ebfSSpencer Ku return false; 2062b7028ebfSSpencer Ku } 2063b7028ebfSSpencer Ku } 2064b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2065b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2066b7028ebfSSpencer Ku if (!lastMessage.empty()) 2067b7028ebfSSpencer Ku { 2068b7028ebfSSpencer Ku logCount++; 2069b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2070b7028ebfSSpencer Ku { 2071b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2072b7028ebfSSpencer Ku } 2073b7028ebfSSpencer Ku } 2074b7028ebfSSpencer Ku return true; 2075b7028ebfSSpencer Ku } 2076b7028ebfSSpencer Ku 2077b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2078b7028ebfSSpencer Ku const std::string& msg, 20796d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2080b7028ebfSSpencer Ku { 2081b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20829c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2083ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2084ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2085ef4c65b7SEd Tanous logEntryID); 20866d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20876d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20886d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20896d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20906d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20916d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2092b7028ebfSSpencer Ku } 2093b7028ebfSSpencer Ku 2094b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2095b7028ebfSSpencer Ku { 209622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2097b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20981476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20991476687dSEd Tanous [&app](const crow::Request& req, 210022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 210122d268cbSEd Tanous const std::string& systemName) { 21023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 210345ca1b86SEd Tanous { 210445ca1b86SEd Tanous return; 210545ca1b86SEd Tanous } 210622d268cbSEd Tanous if (systemName != "system") 210722d268cbSEd Tanous { 210822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 210922d268cbSEd Tanous systemName); 211022d268cbSEd Tanous return; 211122d268cbSEd Tanous } 2112b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2113b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2114b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2115b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2116b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2117b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2118b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21191476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 21201476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2121b7028ebfSSpencer Ku }); 2122b7028ebfSSpencer Ku } 2123b7028ebfSSpencer Ku 2124b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2125b7028ebfSSpencer Ku { 2126b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 212722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2128b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2129002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2130002d39b4SEd Tanous [&app](const crow::Request& req, 213122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 213222d268cbSEd Tanous const std::string& systemName) { 2133c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2134c937d2bfSEd Tanous .canDelegateTop = true, 2135c937d2bfSEd Tanous .canDelegateSkip = true, 2136c937d2bfSEd Tanous }; 2137c937d2bfSEd Tanous query_param::Query delegatedQuery; 2138c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21393ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2140b7028ebfSSpencer Ku { 2141b7028ebfSSpencer Ku return; 2142b7028ebfSSpencer Ku } 214322d268cbSEd Tanous if (systemName != "system") 214422d268cbSEd Tanous { 214522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 214622d268cbSEd Tanous systemName); 214722d268cbSEd Tanous return; 214822d268cbSEd Tanous } 2149b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2150b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2151b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2152b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2153b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2154b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2155b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21560fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2157b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2158b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2159b7028ebfSSpencer Ku 2160b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2161b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2162b7028ebfSSpencer Ku { 2163b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2164b7028ebfSSpencer Ku return; 2165b7028ebfSSpencer Ku } 21663648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21673648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21685143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2169b7028ebfSSpencer Ku size_t logCount = 0; 2170b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2171b7028ebfSSpencer Ku // control by skip and top. 2172b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21733648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21743648c8beSEd Tanous logCount)) 2175b7028ebfSSpencer Ku { 2176b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2177b7028ebfSSpencer Ku return; 2178b7028ebfSSpencer Ku } 2179b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2180b7028ebfSSpencer Ku // log count 218126f6976fSEd Tanous if (logEntries.empty()) 2182b7028ebfSSpencer Ku { 2183b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2184b7028ebfSSpencer Ku return; 2185b7028ebfSSpencer Ku } 218626f6976fSEd Tanous if (!logEntries.empty()) 2187b7028ebfSSpencer Ku { 2188b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2189b7028ebfSSpencer Ku { 21906d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21913648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21923648c8beSEd Tanous hostLogEntry); 2193b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2194b7028ebfSSpencer Ku } 2195b7028ebfSSpencer Ku 2196b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21973648c8beSEd Tanous if (skip + top < logCount) 2198b7028ebfSSpencer Ku { 2199b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 22000fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 22013648c8beSEd Tanous std::to_string(skip + top); 2202b7028ebfSSpencer Ku } 2203b7028ebfSSpencer Ku } 2204b7028ebfSSpencer Ku }); 2205b7028ebfSSpencer Ku } 2206b7028ebfSSpencer Ku 2207b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2208b7028ebfSSpencer Ku { 2209b7028ebfSSpencer Ku BMCWEB_ROUTE( 221022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2211b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2212b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 221345ca1b86SEd Tanous [&app](const crow::Request& req, 2214b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 221522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22163ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 221745ca1b86SEd Tanous { 221845ca1b86SEd Tanous return; 221945ca1b86SEd Tanous } 222022d268cbSEd Tanous if (systemName != "system") 222122d268cbSEd Tanous { 222222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 222322d268cbSEd Tanous systemName); 222422d268cbSEd Tanous return; 222522d268cbSEd Tanous } 2226b7028ebfSSpencer Ku const std::string& targetID = param; 2227b7028ebfSSpencer Ku 2228b7028ebfSSpencer Ku uint64_t idInt = 0; 2229ca45aa3cSEd Tanous 223084396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 223184396af9SPatrick Williams idInt); 22329db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 22339db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2234b7028ebfSSpencer Ku { 22359db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2236b7028ebfSSpencer Ku return; 2237b7028ebfSSpencer Ku } 2238b7028ebfSSpencer Ku 2239b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2240b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2241b7028ebfSSpencer Ku { 2242b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2243b7028ebfSSpencer Ku return; 2244b7028ebfSSpencer Ku } 2245b7028ebfSSpencer Ku 2246b7028ebfSSpencer Ku size_t logCount = 0; 22473648c8beSEd Tanous size_t top = 1; 2248b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2249b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2250b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2251b7028ebfSSpencer Ku // get that entry 2252002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2253002d39b4SEd Tanous logCount)) 2254b7028ebfSSpencer Ku { 2255b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2256b7028ebfSSpencer Ku return; 2257b7028ebfSSpencer Ku } 2258b7028ebfSSpencer Ku 2259b7028ebfSSpencer Ku if (!logEntries.empty()) 2260b7028ebfSSpencer Ku { 22616d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22626d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22636d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2264b7028ebfSSpencer Ku return; 2265b7028ebfSSpencer Ku } 2266b7028ebfSSpencer Ku 2267b7028ebfSSpencer Ku // Requested ID was not found 22689db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2269b7028ebfSSpencer Ku }); 2270b7028ebfSSpencer Ku } 2271b7028ebfSSpencer Ku 2272dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2273fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2274fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22751da66f75SEd Tanous { 22763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 227745ca1b86SEd Tanous { 227845ca1b86SEd Tanous return; 227945ca1b86SEd Tanous } 22807e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22817e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2282e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22831da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2284e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2285e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2286002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2287e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22881da66f75SEd Tanous "Collection of LogServices for this Manager"; 2289002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2290c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2291fdd26906SClaire Weinan 2292c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2293613dabeaSEd Tanous nlohmann::json::object_t journal; 2294613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2295b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2296c4bf6374SJason M. Bills #endif 2297fdd26906SClaire Weinan 2298fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2299fdd26906SClaire Weinan 2300fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 230115912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 23027a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 23037a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 23047a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2305fdd26906SClaire Weinan [asyncResp]( 23067a1dbc48SGeorge Liu const boost::system::error_code& ec, 2307fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2308fdd26906SClaire Weinan if (ec) 2309fdd26906SClaire Weinan { 2310fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2311dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2312fdd26906SClaire Weinan << ec; 2313fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2314fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2315fdd26906SClaire Weinan return; 2316fdd26906SClaire Weinan } 2317fdd26906SClaire Weinan 2318fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2319fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2320fdd26906SClaire Weinan 2321fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2322fdd26906SClaire Weinan { 2323fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2324fdd26906SClaire Weinan { 2325613dabeaSEd Tanous nlohmann::json::object_t member; 2326613dabeaSEd Tanous member["@odata.id"] = 2327613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2328b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2329fdd26906SClaire Weinan } 2330fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2331fdd26906SClaire Weinan { 2332613dabeaSEd Tanous nlohmann::json::object_t member; 2333613dabeaSEd Tanous member["@odata.id"] = 2334613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2335b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2336fdd26906SClaire Weinan } 2337fdd26906SClaire Weinan } 2338fdd26906SClaire Weinan 2339e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2340fdd26906SClaire Weinan logServiceArrayLocal.size(); 23417a1dbc48SGeorge Liu }); 2342fdd26906SClaire Weinan #endif 2343fdd26906SClaire Weinan } 2344fdd26906SClaire Weinan 2345fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2346fdd26906SClaire Weinan { 2347fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2348fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2349fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2350dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2351e1f26343SJason M. Bills } 2352e1f26343SJason M. Bills 23537e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2354e1f26343SJason M. Bills { 23557e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2356ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23577e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 235845ca1b86SEd Tanous [&app](const crow::Request& req, 235945ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23617e860f15SJohn Edward Broadbent { 236245ca1b86SEd Tanous return; 236345ca1b86SEd Tanous } 2364e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2365e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23660f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23670f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2368002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2369002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2370ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2371e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23727c8c4058STejas Patil 23737c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23742b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2375002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23767c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23777c8c4058STejas Patil redfishDateTimeOffset.second; 23787c8c4058STejas Patil 23791476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23801476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23817e860f15SJohn Edward Broadbent }); 2382e1f26343SJason M. Bills } 2383e1f26343SJason M. Bills 23843a48b3a2SJason M. Bills static int 23853a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2386e1f26343SJason M. Bills sd_journal* journal, 23873a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2388e1f26343SJason M. Bills { 2389e1f26343SJason M. Bills // Get the Log Entry contents 2390e1f26343SJason M. Bills int ret = 0; 2391e1f26343SJason M. Bills 2392a8fe54f0SJason M. Bills std::string message; 2393a8fe54f0SJason M. Bills std::string_view syslogID; 2394a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2395a8fe54f0SJason M. Bills if (ret < 0) 2396a8fe54f0SJason M. Bills { 2397a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2398a8fe54f0SJason M. Bills << strerror(-ret); 2399a8fe54f0SJason M. Bills } 2400a8fe54f0SJason M. Bills if (!syslogID.empty()) 2401a8fe54f0SJason M. Bills { 2402a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2403a8fe54f0SJason M. Bills } 2404a8fe54f0SJason M. Bills 240539e77504SEd Tanous std::string_view msg; 240616428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2407e1f26343SJason M. Bills if (ret < 0) 2408e1f26343SJason M. Bills { 2409e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2410e1f26343SJason M. Bills return 1; 2411e1f26343SJason M. Bills } 2412a8fe54f0SJason M. Bills message += std::string(msg); 2413e1f26343SJason M. Bills 2414e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2415271584abSEd Tanous long int severity = 8; // Default to an invalid priority 241616428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2417e1f26343SJason M. Bills if (ret < 0) 2418e1f26343SJason M. Bills { 2419e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2420e1f26343SJason M. Bills } 2421e1f26343SJason M. Bills 2422e1f26343SJason M. Bills // Get the Created time from the timestamp 242316428a1aSJason M. Bills std::string entryTimeStr; 242416428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2425e1f26343SJason M. Bills { 242616428a1aSJason M. Bills return 1; 2427e1f26343SJason M. Bills } 2428e1f26343SJason M. Bills 2429e1f26343SJason M. Bills // Fill in the log entry with the gathered data 24309c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2431ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2432ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2433eddfc437SWilly Tu bmcJournalLogEntryID); 243484afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 243584afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 243684afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 243784afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 243884afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2439738c1e61SPatrick Williams : severity <= 4 ? "Warning" 244084afc48bSJason M. Bills : "OK"; 244184afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 244284afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2443e1f26343SJason M. Bills return 0; 2444e1f26343SJason M. Bills } 2445e1f26343SJason M. Bills 24467e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2447e1f26343SJason M. Bills { 24487e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2449ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2450002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2451002d39b4SEd Tanous [&app](const crow::Request& req, 2452002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2453c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2454c937d2bfSEd Tanous .canDelegateTop = true, 2455c937d2bfSEd Tanous .canDelegateSkip = true, 2456c937d2bfSEd Tanous }; 2457c937d2bfSEd Tanous query_param::Query delegatedQuery; 2458c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24593ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2460193ad2faSJason M. Bills { 2461193ad2faSJason M. Bills return; 2462193ad2faSJason M. Bills } 24633648c8beSEd Tanous 24643648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24655143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24663648c8beSEd Tanous 24677e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24687e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2469e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2470e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24710f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24720f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2473e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2474e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2475e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24760fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2477e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2478e1f26343SJason M. Bills 24797e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24807e860f15SJohn Edward Broadbent // unique ID for each entry 2481e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2482e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2483e1f26343SJason M. Bills if (ret < 0) 2484e1f26343SJason M. Bills { 2485002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2486f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2487e1f26343SJason M. Bills return; 2488e1f26343SJason M. Bills } 24890fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 24900fda0f12SGeorge Liu journalTmp, sd_journal_close); 2491e1f26343SJason M. Bills journalTmp = nullptr; 2492b01bf299SEd Tanous uint64_t entryCount = 0; 2493e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2494e85d6b16SJason M. Bills bool firstEntry = true; 2495e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2496e1f26343SJason M. Bills { 2497193ad2faSJason M. Bills entryCount++; 24987e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 24997e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 25003648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2501193ad2faSJason M. Bills { 2502193ad2faSJason M. Bills continue; 2503193ad2faSJason M. Bills } 2504193ad2faSJason M. Bills 250516428a1aSJason M. Bills std::string idStr; 2506e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2507e1f26343SJason M. Bills { 2508e1f26343SJason M. Bills continue; 2509e1f26343SJason M. Bills } 2510e85d6b16SJason M. Bills firstEntry = false; 2511e85d6b16SJason M. Bills 25123a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2513c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2514c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2515e1f26343SJason M. Bills { 2516f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2517e1f26343SJason M. Bills return; 2518e1f26343SJason M. Bills } 2519b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2520e1f26343SJason M. Bills } 2521193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 25223648c8beSEd Tanous if (skip + top < entryCount) 2523193ad2faSJason M. Bills { 2524193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 25250fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 25263648c8beSEd Tanous std::to_string(skip + top); 2527193ad2faSJason M. Bills } 25287e860f15SJohn Edward Broadbent }); 2529e1f26343SJason M. Bills } 2530e1f26343SJason M. Bills 25317e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2532e1f26343SJason M. Bills { 25337e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 25347e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2535ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 25367e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 253745ca1b86SEd Tanous [&app](const crow::Request& req, 25387e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25397e860f15SJohn Edward Broadbent const std::string& entryID) { 25403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 254145ca1b86SEd Tanous { 254245ca1b86SEd Tanous return; 254345ca1b86SEd Tanous } 2544e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2545e1f26343SJason M. Bills uint64_t ts = 0; 2546271584abSEd Tanous uint64_t index = 0; 25478d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2548e1f26343SJason M. Bills { 254916428a1aSJason M. Bills return; 2550e1f26343SJason M. Bills } 2551e1f26343SJason M. Bills 2552e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2553e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2554e1f26343SJason M. Bills if (ret < 0) 2555e1f26343SJason M. Bills { 2556002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2557f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2558e1f26343SJason M. Bills return; 2559e1f26343SJason M. Bills } 2560002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2561002d39b4SEd Tanous journalTmp, sd_journal_close); 2562e1f26343SJason M. Bills journalTmp = nullptr; 25637e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25647e860f15SJohn Edward Broadbent // index tracking the unique ID 2565af07e3f5SJason M. Bills std::string idStr; 2566af07e3f5SJason M. Bills bool firstEntry = true; 2567e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25682056b6d1SManojkiran Eda if (ret < 0) 25692056b6d1SManojkiran Eda { 25702056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25712056b6d1SManojkiran Eda << strerror(-ret); 25722056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25732056b6d1SManojkiran Eda return; 25742056b6d1SManojkiran Eda } 2575271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2576e1f26343SJason M. Bills { 2577e1f26343SJason M. Bills sd_journal_next(journal.get()); 2578af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2579af07e3f5SJason M. Bills { 2580af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2581af07e3f5SJason M. Bills return; 2582af07e3f5SJason M. Bills } 2583af07e3f5SJason M. Bills firstEntry = false; 2584af07e3f5SJason M. Bills } 2585c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2586af07e3f5SJason M. Bills if (idStr != entryID) 2587c4bf6374SJason M. Bills { 25889db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2589c4bf6374SJason M. Bills return; 2590c4bf6374SJason M. Bills } 2591c4bf6374SJason M. Bills 25923a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2593c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 25943a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2595e1f26343SJason M. Bills { 2596f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2597e1f26343SJason M. Bills return; 2598e1f26343SJason M. Bills } 2599d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 26007e860f15SJohn Edward Broadbent }); 2601c9bb6861Sraviteja-b } 2602c9bb6861Sraviteja-b 2603fdd26906SClaire Weinan inline void 2604fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2605fdd26906SClaire Weinan const std::string& dumpType) 2606c9bb6861Sraviteja-b { 2607fdd26906SClaire Weinan std::string dumpPath; 2608fdd26906SClaire Weinan std::string overWritePolicy; 2609fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2610fdd26906SClaire Weinan 2611fdd26906SClaire Weinan if (dumpType == "BMC") 261245ca1b86SEd Tanous { 2613fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2614fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2615fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2616fdd26906SClaire Weinan } 2617fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2618fdd26906SClaire Weinan { 2619fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2620fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2621fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2622fdd26906SClaire Weinan } 2623fdd26906SClaire Weinan else if (dumpType == "System") 2624fdd26906SClaire Weinan { 2625fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2626fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2627fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2628fdd26906SClaire Weinan } 2629fdd26906SClaire Weinan else 2630fdd26906SClaire Weinan { 2631fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2632fdd26906SClaire Weinan << dumpType; 2633fdd26906SClaire Weinan messages::internalError(asyncResp->res); 263445ca1b86SEd Tanous return; 263545ca1b86SEd Tanous } 2636fdd26906SClaire Weinan 2637fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2638fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2639c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2640fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2641fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2642fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 26437c8c4058STejas Patil 26447c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 26452b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 26460fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 26477c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 26487c8c4058STejas Patil redfishDateTimeOffset.second; 26497c8c4058STejas Patil 2650fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2651fdd26906SClaire Weinan 2652fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2653fdd26906SClaire Weinan { 2654002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26551476687dSEd Tanous ["target"] = 2656fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2657fdd26906SClaire Weinan } 26580d946211SClaire Weinan 26590d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 26600d946211SClaire Weinan dbus::utility::getSubTreePaths( 26610d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 26620d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 26630d946211SClaire Weinan const boost::system::error_code& ec, 26640d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 26650d946211SClaire Weinan if (ec) 26660d946211SClaire Weinan { 26670d946211SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo respHandler got error " 26680d946211SClaire Weinan << ec; 26690d946211SClaire Weinan // Assume that getting an error simply means there are no dump 26700d946211SClaire Weinan // LogServices. Return without adding any error response. 26710d946211SClaire Weinan return; 26720d946211SClaire Weinan } 26730d946211SClaire Weinan 26740d946211SClaire Weinan const std::string dbusDumpPath = 26750d946211SClaire Weinan "/xyz/openbmc_project/dump/" + 26760d946211SClaire Weinan boost::algorithm::to_lower_copy(dumpType); 26770d946211SClaire Weinan 26780d946211SClaire Weinan for (const std::string& path : subTreePaths) 26790d946211SClaire Weinan { 26800d946211SClaire Weinan if (path == dbusDumpPath) 26810d946211SClaire Weinan { 26820d946211SClaire Weinan asyncResp->res 26830d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 26840d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 26850d946211SClaire Weinan break; 26860d946211SClaire Weinan } 26870d946211SClaire Weinan } 26880d946211SClaire Weinan }); 2689c9bb6861Sraviteja-b } 2690c9bb6861Sraviteja-b 2691fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2692fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2693fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 26947e860f15SJohn Edward Broadbent { 26953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 269645ca1b86SEd Tanous { 269745ca1b86SEd Tanous return; 269845ca1b86SEd Tanous } 2699fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2700fdd26906SClaire Weinan } 2701c9bb6861Sraviteja-b 270222d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 270322d268cbSEd Tanous crow::App& app, const crow::Request& req, 270422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 270522d268cbSEd Tanous const std::string& chassisId) 270622d268cbSEd Tanous { 270722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270822d268cbSEd Tanous { 270922d268cbSEd Tanous return; 271022d268cbSEd Tanous } 271122d268cbSEd Tanous if (chassisId != "system") 271222d268cbSEd Tanous { 271322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 271422d268cbSEd Tanous return; 271522d268cbSEd Tanous } 271622d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 271722d268cbSEd Tanous } 271822d268cbSEd Tanous 2719fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2720fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2721fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2722fdd26906SClaire Weinan { 2723fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2724fdd26906SClaire Weinan { 2725fdd26906SClaire Weinan return; 2726fdd26906SClaire Weinan } 2727fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2728fdd26906SClaire Weinan } 2729fdd26906SClaire Weinan 273022d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 273122d268cbSEd Tanous crow::App& app, const crow::Request& req, 273222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 273322d268cbSEd Tanous const std::string& chassisId) 273422d268cbSEd Tanous { 273522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 273622d268cbSEd Tanous { 273722d268cbSEd Tanous return; 273822d268cbSEd Tanous } 273922d268cbSEd Tanous if (chassisId != "system") 274022d268cbSEd Tanous { 274122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 274222d268cbSEd Tanous return; 274322d268cbSEd Tanous } 274422d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 274522d268cbSEd Tanous } 274622d268cbSEd Tanous 2747fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2748fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2749fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2750fdd26906SClaire Weinan const std::string& dumpId) 2751fdd26906SClaire Weinan { 2752fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2753fdd26906SClaire Weinan { 2754fdd26906SClaire Weinan return; 2755fdd26906SClaire Weinan } 2756fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2757fdd26906SClaire Weinan } 275822d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 275922d268cbSEd Tanous crow::App& app, const crow::Request& req, 276022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 276122d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 276222d268cbSEd Tanous { 276322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 276422d268cbSEd Tanous { 276522d268cbSEd Tanous return; 276622d268cbSEd Tanous } 276722d268cbSEd Tanous if (chassisId != "system") 276822d268cbSEd Tanous { 276922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 277022d268cbSEd Tanous return; 277122d268cbSEd Tanous } 277222d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 277322d268cbSEd Tanous } 2774fdd26906SClaire Weinan 2775fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2776fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2777fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2778fdd26906SClaire Weinan const std::string& dumpId) 2779fdd26906SClaire Weinan { 2780fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2781fdd26906SClaire Weinan { 2782fdd26906SClaire Weinan return; 2783fdd26906SClaire Weinan } 2784fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2785fdd26906SClaire Weinan } 2786fdd26906SClaire Weinan 278722d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 278822d268cbSEd Tanous crow::App& app, const crow::Request& req, 278922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 279022d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 279122d268cbSEd Tanous { 279222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 279322d268cbSEd Tanous { 279422d268cbSEd Tanous return; 279522d268cbSEd Tanous } 279622d268cbSEd Tanous if (chassisId != "system") 279722d268cbSEd Tanous { 279822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 279922d268cbSEd Tanous return; 280022d268cbSEd Tanous } 280122d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 280222d268cbSEd Tanous } 280322d268cbSEd Tanous 2804fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2805fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2806fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2807fdd26906SClaire Weinan { 2808fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2809fdd26906SClaire Weinan { 2810fdd26906SClaire Weinan return; 2811fdd26906SClaire Weinan } 2812fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2813fdd26906SClaire Weinan } 2814fdd26906SClaire Weinan 281522d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 281622d268cbSEd Tanous crow::App& app, const crow::Request& req, 281722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 281822d268cbSEd Tanous const std::string& chassisId) 281922d268cbSEd Tanous { 282022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 282122d268cbSEd Tanous { 282222d268cbSEd Tanous return; 282322d268cbSEd Tanous } 282422d268cbSEd Tanous if (chassisId != "system") 282522d268cbSEd Tanous { 282622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 282722d268cbSEd Tanous return; 282822d268cbSEd Tanous } 282922d268cbSEd Tanous createDump(asyncResp, req, "System"); 283022d268cbSEd Tanous } 283122d268cbSEd Tanous 2832fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2833fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2834fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2835fdd26906SClaire Weinan { 2836fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2837fdd26906SClaire Weinan { 2838fdd26906SClaire Weinan return; 2839fdd26906SClaire Weinan } 2840fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2841fdd26906SClaire Weinan } 2842fdd26906SClaire Weinan 284322d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 284422d268cbSEd Tanous crow::App& app, const crow::Request& req, 284522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 284622d268cbSEd Tanous const std::string& chassisId) 284722d268cbSEd Tanous { 284822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 284922d268cbSEd Tanous { 285022d268cbSEd Tanous return; 285122d268cbSEd Tanous } 285222d268cbSEd Tanous if (chassisId != "system") 285322d268cbSEd Tanous { 285422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 285522d268cbSEd Tanous return; 285622d268cbSEd Tanous } 285722d268cbSEd Tanous clearDump(asyncResp, "System"); 285822d268cbSEd Tanous } 285922d268cbSEd Tanous 2860fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2861fdd26906SClaire Weinan { 2862fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2863fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2864fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2865fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2866fdd26906SClaire Weinan } 2867fdd26906SClaire Weinan 2868fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2869fdd26906SClaire Weinan { 2870fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2871fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2872fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2873fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2874c9bb6861Sraviteja-b } 2875c9bb6861Sraviteja-b 28767e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2877c9bb6861Sraviteja-b { 28787e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28797e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2880ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2881fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2882fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2883fdd26906SClaire Weinan 28847e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28857e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2886ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2887fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2888fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2889c9bb6861Sraviteja-b } 2890c9bb6861Sraviteja-b 28917e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2892c9bb6861Sraviteja-b { 28930fda0f12SGeorge Liu BMCWEB_ROUTE( 28940fda0f12SGeorge Liu app, 28950fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2896ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28977e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2898fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2899fdd26906SClaire Weinan std::ref(app), "BMC")); 2900a43be80fSAsmitha Karunanithi } 2901a43be80fSAsmitha Karunanithi 29027e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 290380319af1SAsmitha Karunanithi { 29040fda0f12SGeorge Liu BMCWEB_ROUTE( 29050fda0f12SGeorge Liu app, 29060fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2907ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2908fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2909fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 291045ca1b86SEd Tanous } 2911fdd26906SClaire Weinan 2912fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2913fdd26906SClaire Weinan { 2914fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2915fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2916fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2917fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2918fdd26906SClaire Weinan } 2919fdd26906SClaire Weinan 2920fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2921fdd26906SClaire Weinan { 2922fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2923fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2924fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2925fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2926fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2927fdd26906SClaire Weinan } 2928fdd26906SClaire Weinan 2929fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2930fdd26906SClaire Weinan { 2931fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2932fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2933fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2934fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2935fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2936fdd26906SClaire Weinan 2937fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2938fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2939fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2940fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2941fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2942fdd26906SClaire Weinan } 2943fdd26906SClaire Weinan 2944fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2945fdd26906SClaire Weinan { 2946fdd26906SClaire Weinan BMCWEB_ROUTE( 2947fdd26906SClaire Weinan app, 2948fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2949fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2950fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2951fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 29525cb1dd27SAsmitha Karunanithi } 29535cb1dd27SAsmitha Karunanithi 29547e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 29555cb1dd27SAsmitha Karunanithi { 295622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2957ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 29586ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 295922d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 29605cb1dd27SAsmitha Karunanithi } 29615cb1dd27SAsmitha Karunanithi 29627e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 29637e860f15SJohn Edward Broadbent { 296422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2965ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 296622d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 296722d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 296822d268cbSEd Tanous std::ref(app))); 29695cb1dd27SAsmitha Karunanithi } 29705cb1dd27SAsmitha Karunanithi 29717e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 29725cb1dd27SAsmitha Karunanithi { 29737e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 297422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2975ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29766ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 297722d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29788d1b46d7Szhanghch05 29797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 298022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2981ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29826ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 298322d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29845cb1dd27SAsmitha Karunanithi } 2985c9bb6861Sraviteja-b 29867e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2987c9bb6861Sraviteja-b { 29880fda0f12SGeorge Liu BMCWEB_ROUTE( 29890fda0f12SGeorge Liu app, 299022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2991ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 299222d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 299322d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 299422d268cbSEd Tanous std::ref(app))); 2995a43be80fSAsmitha Karunanithi } 2996a43be80fSAsmitha Karunanithi 29977e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2998a43be80fSAsmitha Karunanithi { 29990fda0f12SGeorge Liu BMCWEB_ROUTE( 30000fda0f12SGeorge Liu app, 300122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3002ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 30036ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 300422d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3005013487e5Sraviteja-b } 3006013487e5Sraviteja-b 30077e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 30081da66f75SEd Tanous { 30093946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30103946028dSAppaRao Puli // method for security reasons. 30111da66f75SEd Tanous /** 30121da66f75SEd Tanous * Functions triggers appropriate requests on DBus 30131da66f75SEd Tanous */ 301422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3015ed398213SEd Tanous // This is incorrect, should be: 3016ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3017432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3018002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3019002d39b4SEd Tanous [&app](const crow::Request& req, 302022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 302122d268cbSEd Tanous const std::string& systemName) { 30223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 302345ca1b86SEd Tanous { 302445ca1b86SEd Tanous return; 302545ca1b86SEd Tanous } 302622d268cbSEd Tanous if (systemName != "system") 302722d268cbSEd Tanous { 302822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 302922d268cbSEd Tanous systemName); 303022d268cbSEd Tanous return; 303122d268cbSEd Tanous } 303222d268cbSEd Tanous 30337e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 30347e860f15SJohn Edward Broadbent // SubRoute 30350f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3036424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3037e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 30388e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 30394f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 30404f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 304115b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3042e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3043e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 30447c8c4058STejas Patil 30457c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 30462b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 30477c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 30487c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 30497c8c4058STejas Patil redfishDateTimeOffset.second; 30507c8c4058STejas Patil 30511476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3052ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3053002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 30541476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3055002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 30561476687dSEd Tanous ["target"] = 30571476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 30587e860f15SJohn Edward Broadbent }); 30591da66f75SEd Tanous } 30601da66f75SEd Tanous 30617e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30625b61b5e8SJason M. Bills { 30630fda0f12SGeorge Liu BMCWEB_ROUTE( 30640fda0f12SGeorge Liu app, 306522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3066ed398213SEd Tanous // This is incorrect, should be: 3067ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3068432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 307045ca1b86SEd Tanous [&app](const crow::Request& req, 307122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 307222d268cbSEd Tanous const std::string& systemName) { 30733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 307445ca1b86SEd Tanous { 307545ca1b86SEd Tanous return; 307645ca1b86SEd Tanous } 307722d268cbSEd Tanous if (systemName != "system") 307822d268cbSEd Tanous { 307922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 308022d268cbSEd Tanous systemName); 308122d268cbSEd Tanous return; 308222d268cbSEd Tanous } 30835b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30845e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3085cb13a392SEd Tanous const std::string&) { 30865b61b5e8SJason M. Bills if (ec) 30875b61b5e8SJason M. Bills { 30885b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30895b61b5e8SJason M. Bills return; 30905b61b5e8SJason M. Bills } 30915b61b5e8SJason M. Bills messages::success(asyncResp->res); 30925b61b5e8SJason M. Bills }, 3093002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30947e860f15SJohn Edward Broadbent }); 30955b61b5e8SJason M. Bills } 30965b61b5e8SJason M. Bills 30978d1b46d7Szhanghch05 static void 30988d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30998d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3100e855dd28SJason M. Bills { 3101043a0536SJohnathan Mantey auto getStoredLogCallback = 3102b9d36b47SEd Tanous [asyncResp, logID, 31035e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3104b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3105e855dd28SJason M. Bills if (ec) 3106e855dd28SJason M. Bills { 3107e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 31081ddcf01aSJason M. Bills if (ec.value() == 31091ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 31101ddcf01aSJason M. Bills { 3111002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 31121ddcf01aSJason M. Bills } 31131ddcf01aSJason M. Bills else 31141ddcf01aSJason M. Bills { 3115e855dd28SJason M. Bills messages::internalError(asyncResp->res); 31161ddcf01aSJason M. Bills } 3117e855dd28SJason M. Bills return; 3118e855dd28SJason M. Bills } 3119043a0536SJohnathan Mantey 3120043a0536SJohnathan Mantey std::string timestamp{}; 3121043a0536SJohnathan Mantey std::string filename{}; 3122043a0536SJohnathan Mantey std::string logfile{}; 31232c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3124043a0536SJohnathan Mantey 3125043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3126e855dd28SJason M. Bills { 31279db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3128e855dd28SJason M. Bills return; 3129e855dd28SJason M. Bills } 3130e855dd28SJason M. Bills 3131043a0536SJohnathan Mantey std::string crashdumpURI = 3132e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3133043a0536SJohnathan Mantey logID + "/" + filename; 313484afc48bSJason M. Bills nlohmann::json::object_t logEntry; 31359c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3136ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3137ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3138ef4c65b7SEd Tanous logID); 313984afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 314084afc48bSJason M. Bills logEntry["Id"] = logID; 314184afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 314284afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 314384afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 314484afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 314584afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 31462b20ef6eSJason M. Bills 31472b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 31482b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 31492b20ef6eSJason M. Bills // directly 31502b20ef6eSJason M. Bills if (logEntryJson.is_array()) 31512b20ef6eSJason M. Bills { 31522b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 31532b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 31542b20ef6eSJason M. Bills logEntryJson.size(); 31552b20ef6eSJason M. Bills } 31562b20ef6eSJason M. Bills else 31572b20ef6eSJason M. Bills { 3158d405bb51SJason M. Bills logEntryJson.update(logEntry); 31592b20ef6eSJason M. Bills } 3160e855dd28SJason M. Bills }; 3161d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3162d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3163d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3164d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3165e855dd28SJason M. Bills } 3166e855dd28SJason M. Bills 31677e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31681da66f75SEd Tanous { 31693946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31703946028dSAppaRao Puli // method for security reasons. 31711da66f75SEd Tanous /** 31721da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31731da66f75SEd Tanous */ 31747e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 317522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3176ed398213SEd Tanous // This is incorrect, should be. 3177ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3178432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3179002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3180002d39b4SEd Tanous [&app](const crow::Request& req, 318122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 318222d268cbSEd Tanous const std::string& systemName) { 31833ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 318445ca1b86SEd Tanous { 318545ca1b86SEd Tanous return; 318645ca1b86SEd Tanous } 318722d268cbSEd Tanous if (systemName != "system") 318822d268cbSEd Tanous { 318922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 319022d268cbSEd Tanous systemName); 319122d268cbSEd Tanous return; 319222d268cbSEd Tanous } 319322d268cbSEd Tanous 31947a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 31957a1dbc48SGeorge Liu crashdumpInterface}; 31967a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 31977a1dbc48SGeorge Liu "/", 0, interfaces, 31987a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 31992b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 32001da66f75SEd Tanous if (ec) 32011da66f75SEd Tanous { 32021da66f75SEd Tanous if (ec.value() != 32031da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 32041da66f75SEd Tanous { 32051da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 32061da66f75SEd Tanous << ec.message(); 3207f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32081da66f75SEd Tanous return; 32091da66f75SEd Tanous } 32101da66f75SEd Tanous } 3211e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32121da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 32130f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3214424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3215002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3216e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3217424c4176SJason M. Bills "Collection of Crashdump Entries"; 3218002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3219a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 32202b20ef6eSJason M. Bills 32212b20ef6eSJason M. Bills for (const std::string& path : resp) 32221da66f75SEd Tanous { 32232b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3224e855dd28SJason M. Bills // Get the log ID 32252b20ef6eSJason M. Bills std::string logID = objPath.filename(); 32262b20ef6eSJason M. Bills if (logID.empty()) 32271da66f75SEd Tanous { 3228e855dd28SJason M. Bills continue; 32291da66f75SEd Tanous } 3230e855dd28SJason M. Bills // Add the log entry to the array 32312b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 32322b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 32331da66f75SEd Tanous } 32347a1dbc48SGeorge Liu }); 32357e860f15SJohn Edward Broadbent }); 32361da66f75SEd Tanous } 32371da66f75SEd Tanous 32387e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 32391da66f75SEd Tanous { 32403946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32413946028dSAppaRao Puli // method for security reasons. 32421da66f75SEd Tanous 32437e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 324422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3245ed398213SEd Tanous // this is incorrect, should be 3246ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3247432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 324945ca1b86SEd Tanous [&app](const crow::Request& req, 32507e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 325122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 32523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 325345ca1b86SEd Tanous { 325445ca1b86SEd Tanous return; 325545ca1b86SEd Tanous } 325622d268cbSEd Tanous if (systemName != "system") 325722d268cbSEd Tanous { 325822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 325922d268cbSEd Tanous systemName); 326022d268cbSEd Tanous return; 326122d268cbSEd Tanous } 32627e860f15SJohn Edward Broadbent const std::string& logID = param; 3263e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32647e860f15SJohn Edward Broadbent }); 3265e855dd28SJason M. Bills } 3266e855dd28SJason M. Bills 32677e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3268e855dd28SJason M. Bills { 32693946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32703946028dSAppaRao Puli // method for security reasons. 32717e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32727e860f15SJohn Edward Broadbent app, 327322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3274ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32757e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3276a4ce114aSNan Zhou [](const crow::Request& req, 32777e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 327822d268cbSEd Tanous const std::string& systemName, const std::string& logID, 327922d268cbSEd Tanous const std::string& fileName) { 32802a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32812a9beeedSShounak Mitra // Redfish resource. 328222d268cbSEd Tanous 328322d268cbSEd Tanous if (systemName != "system") 328422d268cbSEd Tanous { 328522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 328622d268cbSEd Tanous systemName); 328722d268cbSEd Tanous return; 328822d268cbSEd Tanous } 328922d268cbSEd Tanous 3290043a0536SJohnathan Mantey auto getStoredLogCallback = 329139662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 32925e7e2dc5SEd Tanous const boost::system::error_code& ec, 3293002d39b4SEd Tanous const std::vector< 3294002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32957e860f15SJohn Edward Broadbent resp) { 32961da66f75SEd Tanous if (ec) 32971da66f75SEd Tanous { 3298002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3299f12894f8SJason M. Bills messages::internalError(asyncResp->res); 33001da66f75SEd Tanous return; 33011da66f75SEd Tanous } 3302e855dd28SJason M. Bills 3303043a0536SJohnathan Mantey std::string dbusFilename{}; 3304043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3305043a0536SJohnathan Mantey std::string dbusFilepath{}; 3306043a0536SJohnathan Mantey 3307002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3308002d39b4SEd Tanous dbusFilepath); 3309043a0536SJohnathan Mantey 3310043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3311043a0536SJohnathan Mantey dbusFilepath.empty()) 33121da66f75SEd Tanous { 33139db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33141da66f75SEd Tanous return; 33151da66f75SEd Tanous } 3316e855dd28SJason M. Bills 3317043a0536SJohnathan Mantey // Verify the file name parameter is correct 3318043a0536SJohnathan Mantey if (fileName != dbusFilename) 3319043a0536SJohnathan Mantey { 33209db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3321043a0536SJohnathan Mantey return; 3322043a0536SJohnathan Mantey } 3323043a0536SJohnathan Mantey 3324043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3325043a0536SJohnathan Mantey { 33269db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3327043a0536SJohnathan Mantey return; 3328043a0536SJohnathan Mantey } 3329002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3330002d39b4SEd Tanous asyncResp->res.body() = 3331002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3332043a0536SJohnathan Mantey 33337e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 33347e860f15SJohn Edward Broadbent // from a browser 3335d9f6c621SEd Tanous asyncResp->res.addHeader( 3336d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 33371da66f75SEd Tanous }; 3338d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3339d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3340d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3341d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 33427e860f15SJohn Edward Broadbent }); 33431da66f75SEd Tanous } 33441da66f75SEd Tanous 3345c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3346c5a4c82aSJason M. Bills { 3347c5a4c82aSJason M. Bills onDemand, 3348c5a4c82aSJason M. Bills telemetry, 3349c5a4c82aSJason M. Bills invalid, 3350c5a4c82aSJason M. Bills }; 3351c5a4c82aSJason M. Bills 335226ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3353c5a4c82aSJason M. Bills { 3354c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3355c5a4c82aSJason M. Bills { 3356c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3357c5a4c82aSJason M. Bills } 3358c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3359c5a4c82aSJason M. Bills { 3360c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3361c5a4c82aSJason M. Bills } 3362c5a4c82aSJason M. Bills 3363c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3364c5a4c82aSJason M. Bills } 3365c5a4c82aSJason M. Bills 33667e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33671da66f75SEd Tanous { 33683946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33693946028dSAppaRao Puli // method for security reasons. 33700fda0f12SGeorge Liu BMCWEB_ROUTE( 33710fda0f12SGeorge Liu app, 337222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3373ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3374ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3375432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3376002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3377002d39b4SEd Tanous [&app](const crow::Request& req, 337822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 337922d268cbSEd Tanous const std::string& systemName) { 33803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 338145ca1b86SEd Tanous { 338245ca1b86SEd Tanous return; 338345ca1b86SEd Tanous } 338422d268cbSEd Tanous 338522d268cbSEd Tanous if (systemName != "system") 338622d268cbSEd Tanous { 338722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 338822d268cbSEd Tanous systemName); 338922d268cbSEd Tanous return; 339022d268cbSEd Tanous } 339122d268cbSEd Tanous 33928e6c099aSJason M. Bills std::string diagnosticDataType; 33938e6c099aSJason M. Bills std::string oemDiagnosticDataType; 339415ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3395002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3396002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33978e6c099aSJason M. Bills { 33988e6c099aSJason M. Bills return; 33998e6c099aSJason M. Bills } 34008e6c099aSJason M. Bills 34018e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 34028e6c099aSJason M. Bills { 34038e6c099aSJason M. Bills BMCWEB_LOG_ERROR 34048e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 34058e6c099aSJason M. Bills messages::actionParameterValueFormatError( 34068e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 34078e6c099aSJason M. Bills "CollectDiagnosticData"); 34088e6c099aSJason M. Bills return; 34098e6c099aSJason M. Bills } 34108e6c099aSJason M. Bills 3411c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3412c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3413c5a4c82aSJason M. Bills 3414c5a4c82aSJason M. Bills std::string iface; 3415c5a4c82aSJason M. Bills std::string method; 3416c5a4c82aSJason M. Bills std::string taskMatchStr; 3417c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3418c5a4c82aSJason M. Bills { 3419c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3420c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3421c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3422c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3423c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3424c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3425c5a4c82aSJason M. Bills } 3426c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3427c5a4c82aSJason M. Bills { 3428c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3429c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3430c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3431c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3432c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3433c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3434c5a4c82aSJason M. Bills } 3435c5a4c82aSJason M. Bills else 3436c5a4c82aSJason M. Bills { 3437c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3438c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3439c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3440002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3441002d39b4SEd Tanous "CollectDiagnosticData"); 3442c5a4c82aSJason M. Bills return; 3443c5a4c82aSJason M. Bills } 3444c5a4c82aSJason M. Bills 3445c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3446c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 34475e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 344898be3e39SEd Tanous const std::string&) mutable { 34491da66f75SEd Tanous if (ec) 34501da66f75SEd Tanous { 3451002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 34521da66f75SEd Tanous { 3453f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 34541da66f75SEd Tanous } 34554363d3b2SJason M. Bills else if (ec.value() == 34564363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 34574363d3b2SJason M. Bills { 3458002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3459002d39b4SEd Tanous "60"); 34604363d3b2SJason M. Bills } 34611da66f75SEd Tanous else 34621da66f75SEd Tanous { 3463f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34641da66f75SEd Tanous } 34651da66f75SEd Tanous return; 34661da66f75SEd Tanous } 3467002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 34685e7e2dc5SEd Tanous [](const boost::system::error_code& err, sdbusplus::message_t&, 3469002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 347066afe4faSJames Feist if (!err) 347166afe4faSJames Feist { 3472002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3473e5d5006bSJames Feist std::to_string(taskData->index))); 3474831d6b09SJames Feist taskData->state = "Completed"; 347566afe4faSJames Feist } 347632898ceaSJames Feist return task::completed; 347766afe4faSJames Feist }, 3478c5a4c82aSJason M. Bills taskMatchStr); 3479c5a4c82aSJason M. Bills 348046229577SJames Feist task->startTimer(std::chrono::minutes(5)); 348146229577SJames Feist task->populateResp(asyncResp->res); 348298be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34831da66f75SEd Tanous }; 34848e6c099aSJason M. Bills 34851da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3486002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3487002d39b4SEd Tanous iface, method); 34887e860f15SJohn Edward Broadbent }); 34896eda7685SKenny L. Ku } 34906eda7685SKenny L. Ku 3491cb92c03bSAndrew Geissler /** 3492cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3493cb92c03bSAndrew Geissler */ 34947e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3495cb92c03bSAndrew Geissler { 3496cb92c03bSAndrew Geissler /** 3497cb92c03bSAndrew Geissler * Function handles POST method request. 3498cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3499cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3500cb92c03bSAndrew Geissler */ 35017e860f15SJohn Edward Broadbent 35020fda0f12SGeorge Liu BMCWEB_ROUTE( 35030fda0f12SGeorge Liu app, 350422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3505ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 35067e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 350745ca1b86SEd Tanous [&app](const crow::Request& req, 350822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350922d268cbSEd Tanous const std::string& systemName) { 35103ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 351145ca1b86SEd Tanous { 351245ca1b86SEd Tanous return; 351345ca1b86SEd Tanous } 351422d268cbSEd Tanous if (systemName != "system") 351522d268cbSEd Tanous { 351622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 351722d268cbSEd Tanous systemName); 351822d268cbSEd Tanous return; 351922d268cbSEd Tanous } 3520cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3521cb92c03bSAndrew Geissler 3522cb92c03bSAndrew Geissler // Process response from Logging service. 35235e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 3524002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3525cb92c03bSAndrew Geissler if (ec) 3526cb92c03bSAndrew Geissler { 3527cb92c03bSAndrew Geissler // TODO Handle for specific error code 3528002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3529cb92c03bSAndrew Geissler asyncResp->res.result( 3530cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3531cb92c03bSAndrew Geissler return; 3532cb92c03bSAndrew Geissler } 3533cb92c03bSAndrew Geissler 3534002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3535cb92c03bSAndrew Geissler }; 3536cb92c03bSAndrew Geissler 3537cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3538cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 35392c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3540cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3541cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35427e860f15SJohn Edward Broadbent }); 3543cb92c03bSAndrew Geissler } 3544a3316fc6SZhikuiRen 3545a3316fc6SZhikuiRen /**************************************************** 3546a3316fc6SZhikuiRen * Redfish PostCode interfaces 3547a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3548a3316fc6SZhikuiRen ******************************************************/ 35497e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3550a3316fc6SZhikuiRen { 355122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3552ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3553002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3554002d39b4SEd Tanous [&app](const crow::Request& req, 355522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 355622d268cbSEd Tanous const std::string& systemName) { 35573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 355845ca1b86SEd Tanous { 355945ca1b86SEd Tanous return; 356045ca1b86SEd Tanous } 356122d268cbSEd Tanous if (systemName != "system") 356222d268cbSEd Tanous { 356322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 356422d268cbSEd Tanous systemName); 356522d268cbSEd Tanous return; 356622d268cbSEd Tanous } 35671476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 35681476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 35691476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 35701476687dSEd Tanous "#LogService.v1_1_0.LogService"; 35711476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35721476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3573ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 35741476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35751476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35761476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35777c8c4058STejas Patil 35787c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35792b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35800fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35817c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35827c8c4058STejas Patil redfishDateTimeOffset.second; 35837c8c4058STejas Patil 3584a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 35857e860f15SJohn Edward Broadbent {"target", 35860fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 35877e860f15SJohn Edward Broadbent }); 3588a3316fc6SZhikuiRen } 3589a3316fc6SZhikuiRen 35907e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3591a3316fc6SZhikuiRen { 35920fda0f12SGeorge Liu BMCWEB_ROUTE( 35930fda0f12SGeorge Liu app, 359422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3595ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3596ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3597432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 359945ca1b86SEd Tanous [&app](const crow::Request& req, 360022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 360122d268cbSEd Tanous const std::string& systemName) { 36023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 360345ca1b86SEd Tanous { 360445ca1b86SEd Tanous return; 360545ca1b86SEd Tanous } 360622d268cbSEd Tanous if (systemName != "system") 360722d268cbSEd Tanous { 360822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 360922d268cbSEd Tanous systemName); 361022d268cbSEd Tanous return; 361122d268cbSEd Tanous } 3612a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3613a3316fc6SZhikuiRen 3614a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3615a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 36165e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3617a3316fc6SZhikuiRen if (ec) 3618a3316fc6SZhikuiRen { 3619a3316fc6SZhikuiRen // TODO Handle for specific error code 3620002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 36217e860f15SJohn Edward Broadbent << ec; 3622002d39b4SEd Tanous asyncResp->res.result( 3623002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3624a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3625a3316fc6SZhikuiRen return; 3626a3316fc6SZhikuiRen } 3627a3316fc6SZhikuiRen }, 362815124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 362915124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3630a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 36317e860f15SJohn Edward Broadbent }); 3632a3316fc6SZhikuiRen } 3633a3316fc6SZhikuiRen 36346f284d24SJiaqing Zhao /** 36356f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 36366f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 36376f284d24SJiaqing Zhao * 36386f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 36396f284d24SJiaqing Zhao * @param[out] currentValue Current value 36406f284d24SJiaqing Zhao * @param[out] index Index value 36416f284d24SJiaqing Zhao * 36426f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 36436f284d24SJiaqing Zhao */ 36446f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 36456f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 36466f284d24SJiaqing Zhao { 36476f284d24SJiaqing Zhao std::vector<std::string> split; 364850ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 36496f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 36506f284d24SJiaqing Zhao { 36516f284d24SJiaqing Zhao return false; 36526f284d24SJiaqing Zhao } 36536f284d24SJiaqing Zhao 365484396af9SPatrick Williams auto start = std::next(split[0].begin()); 365584396af9SPatrick Williams auto end = split[0].end(); 365684396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 36576f284d24SJiaqing Zhao 365884396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 36596f284d24SJiaqing Zhao { 36606f284d24SJiaqing Zhao return false; 36616f284d24SJiaqing Zhao } 36626f284d24SJiaqing Zhao 366384396af9SPatrick Williams start = split[1].begin(); 366484396af9SPatrick Williams end = split[1].end(); 36656f284d24SJiaqing Zhao 366684396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 36676f284d24SJiaqing Zhao 366884396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 36696f284d24SJiaqing Zhao } 36706f284d24SJiaqing Zhao 36716f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3672ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36736c9a279eSManojkiran Eda const boost::container::flat_map< 36746c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3675a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3676a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3677a3316fc6SZhikuiRen { 3678a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3679fffb8c1fSEd Tanous const registries::Message* message = 3680fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3681a3316fc6SZhikuiRen 3682a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3683a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 36846c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36856c9a279eSManojkiran Eda code : postcode) 3686a3316fc6SZhikuiRen { 3687a3316fc6SZhikuiRen currentCodeIndex++; 3688a3316fc6SZhikuiRen std::string postcodeEntryID = 3689a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3690a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3691a3316fc6SZhikuiRen 3692a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3693a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3694a3316fc6SZhikuiRen 3695a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3696a3316fc6SZhikuiRen { // already incremented 3697a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3698a3316fc6SZhikuiRen } 3699a3316fc6SZhikuiRen else 3700a3316fc6SZhikuiRen { 3701a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3702a3316fc6SZhikuiRen } 3703a3316fc6SZhikuiRen 3704a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3705a3316fc6SZhikuiRen // not fall between top and skip 3706a3316fc6SZhikuiRen if ((codeIndex == 0) && 3707a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3708a3316fc6SZhikuiRen { 3709a3316fc6SZhikuiRen continue; 3710a3316fc6SZhikuiRen } 3711a3316fc6SZhikuiRen 37124e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3713a3316fc6SZhikuiRen // currentIndex 3714a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3715a3316fc6SZhikuiRen { 3716a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3717a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3718a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3719a3316fc6SZhikuiRen continue; 3720a3316fc6SZhikuiRen } 3721a3316fc6SZhikuiRen 3722a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3723a3316fc6SZhikuiRen // index 3724a3316fc6SZhikuiRen 3725a3316fc6SZhikuiRen // Get the Created time from the timestamp 3726a3316fc6SZhikuiRen std::string entryTimeStr; 37272a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3728a3316fc6SZhikuiRen 3729a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3730a3316fc6SZhikuiRen std::ostringstream hexCode; 3731a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 37326c9a279eSManojkiran Eda << std::get<0>(code.second); 3733a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3734a3316fc6SZhikuiRen // Set Fixed -Point Notation 3735a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3736a3316fc6SZhikuiRen // Set precision to 4 digits 3737a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3738a3316fc6SZhikuiRen // Add double to stream 3739a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3740a3316fc6SZhikuiRen 3741*1e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 3742*1e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 3743*1e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3744a3316fc6SZhikuiRen 3745*1e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 3746*1e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 3747*1e6deaf6SEd Tanous 3748*1e6deaf6SEd Tanous std::string msg = 3749*1e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 3750*1e6deaf6SEd Tanous if (msg.empty()) 3751a3316fc6SZhikuiRen { 3752*1e6deaf6SEd Tanous messages::internalError(asyncResp->res); 3753*1e6deaf6SEd Tanous return false; 3754a3316fc6SZhikuiRen } 3755a3316fc6SZhikuiRen 3756d4342a92STim Lee // Get Severity template from message registry 3757d4342a92STim Lee std::string severity; 3758d4342a92STim Lee if (message != nullptr) 3759d4342a92STim Lee { 37605f2b84eeSEd Tanous severity = message->messageSeverity; 3761d4342a92STim Lee } 3762d4342a92STim Lee 37636f284d24SJiaqing Zhao // Format entry 37646f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37659c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3766ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 3767ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 3768ef4c65b7SEd Tanous postcodeEntryID); 376984afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 377084afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 377184afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 377284afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 3773*1e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 377484afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 377584afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 377684afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3777647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3778647b3cdcSGeorge Liu { 3779647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3780647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3781647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3782647b3cdcSGeorge Liu } 37836f284d24SJiaqing Zhao 37846f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 37856f284d24SJiaqing Zhao // that entry in this case 37866f284d24SJiaqing Zhao if (codeIndex != 0) 37876f284d24SJiaqing Zhao { 3788ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 37896f284d24SJiaqing Zhao return true; 3790a3316fc6SZhikuiRen } 37916f284d24SJiaqing Zhao 3792ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3793b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 37946f284d24SJiaqing Zhao } 37956f284d24SJiaqing Zhao 37966f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 37976f284d24SJiaqing Zhao return false; 3798a3316fc6SZhikuiRen } 3799a3316fc6SZhikuiRen 3800ac106bf6SEd Tanous static void 3801ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 38026f284d24SJiaqing Zhao const std::string& entryId) 3803a3316fc6SZhikuiRen { 38046f284d24SJiaqing Zhao uint16_t bootIndex = 0; 38056f284d24SJiaqing Zhao uint64_t codeIndex = 0; 38066f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 38076f284d24SJiaqing Zhao { 38086f284d24SJiaqing Zhao // Requested ID was not found 3809ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38106f284d24SJiaqing Zhao return; 38116f284d24SJiaqing Zhao } 38126f284d24SJiaqing Zhao 38136f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 38146f284d24SJiaqing Zhao { 38156f284d24SJiaqing Zhao // 0 is an invalid index 3816ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38176f284d24SJiaqing Zhao return; 38186f284d24SJiaqing Zhao } 38196f284d24SJiaqing Zhao 3820a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3821ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 38225e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 38236c9a279eSManojkiran Eda const boost::container::flat_map< 38246c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38256c9a279eSManojkiran Eda postcode) { 3826a3316fc6SZhikuiRen if (ec) 3827a3316fc6SZhikuiRen { 3828a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3829ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3830a3316fc6SZhikuiRen return; 3831a3316fc6SZhikuiRen } 3832a3316fc6SZhikuiRen 3833a3316fc6SZhikuiRen if (postcode.empty()) 3834a3316fc6SZhikuiRen { 3835ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3836a3316fc6SZhikuiRen return; 3837a3316fc6SZhikuiRen } 3838a3316fc6SZhikuiRen 3839ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 38406f284d24SJiaqing Zhao { 3841ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 38426f284d24SJiaqing Zhao return; 38436f284d24SJiaqing Zhao } 3844a3316fc6SZhikuiRen }, 384515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 384615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3847a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3848a3316fc6SZhikuiRen bootIndex); 3849a3316fc6SZhikuiRen } 3850a3316fc6SZhikuiRen 3851ac106bf6SEd Tanous static void 3852ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3853ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 3854ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 3855a3316fc6SZhikuiRen { 3856a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3857ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 38585e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 38596c9a279eSManojkiran Eda const boost::container::flat_map< 38606c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38616c9a279eSManojkiran Eda postcode) { 3862a3316fc6SZhikuiRen if (ec) 3863a3316fc6SZhikuiRen { 3864a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3865ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3866a3316fc6SZhikuiRen return; 3867a3316fc6SZhikuiRen } 3868a3316fc6SZhikuiRen 3869a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3870a3316fc6SZhikuiRen if (!postcode.empty()) 3871a3316fc6SZhikuiRen { 3872a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38733648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3874a3316fc6SZhikuiRen { 387589492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 387689492a15SPatrick Williams entryCount) - 38773648c8beSEd Tanous entryCount; 3878a3316fc6SZhikuiRen uint64_t thisBootTop = 38793648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38803648c8beSEd Tanous entryCount; 3881a3316fc6SZhikuiRen 3882ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 3883ac106bf6SEd Tanous thisBootSkip, thisBootTop); 3884a3316fc6SZhikuiRen } 3885ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 3886a3316fc6SZhikuiRen } 3887a3316fc6SZhikuiRen 3888a3316fc6SZhikuiRen // continue to previous bootIndex 3889a3316fc6SZhikuiRen if (bootIndex < bootCount) 3890a3316fc6SZhikuiRen { 3891ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 3892a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3893a3316fc6SZhikuiRen } 389481584abeSJiaqing Zhao else if (skip + top < endCount) 3895a3316fc6SZhikuiRen { 3896ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 38970fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3898a3316fc6SZhikuiRen std::to_string(skip + top); 3899a3316fc6SZhikuiRen } 3900a3316fc6SZhikuiRen }, 390115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 390215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3903a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3904a3316fc6SZhikuiRen bootIndex); 3905a3316fc6SZhikuiRen } 3906a3316fc6SZhikuiRen 39078d1b46d7Szhanghch05 static void 3908ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39093648c8beSEd Tanous size_t skip, size_t top) 3910a3316fc6SZhikuiRen { 3911a3316fc6SZhikuiRen uint64_t entryCount = 0; 39121e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 39131e1e598dSJonathan Doman *crow::connections::systemBus, 39141e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 39151e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 39161e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 3917ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 39181e1e598dSJonathan Doman const uint16_t bootCount) { 3919a3316fc6SZhikuiRen if (ec) 3920a3316fc6SZhikuiRen { 3921a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3922ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3923a3316fc6SZhikuiRen return; 3924a3316fc6SZhikuiRen } 3925ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 39261e1e598dSJonathan Doman }); 3927a3316fc6SZhikuiRen } 3928a3316fc6SZhikuiRen 39297e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3930a3316fc6SZhikuiRen { 39317e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 393222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3933ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 39347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 393545ca1b86SEd Tanous [&app](const crow::Request& req, 393622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 393722d268cbSEd Tanous const std::string& systemName) { 3938c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3939c937d2bfSEd Tanous .canDelegateTop = true, 3940c937d2bfSEd Tanous .canDelegateSkip = true, 3941c937d2bfSEd Tanous }; 3942c937d2bfSEd Tanous query_param::Query delegatedQuery; 3943c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39443ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 394545ca1b86SEd Tanous { 394645ca1b86SEd Tanous return; 394745ca1b86SEd Tanous } 394822d268cbSEd Tanous 394922d268cbSEd Tanous if (systemName != "system") 395022d268cbSEd Tanous { 395122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 395222d268cbSEd Tanous systemName); 395322d268cbSEd Tanous return; 395422d268cbSEd Tanous } 3955a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3956a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3957a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3958a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3959a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3960a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3961a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3962a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3963a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39643648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39655143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39663648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39677e860f15SJohn Edward Broadbent }); 3968a3316fc6SZhikuiRen } 3969a3316fc6SZhikuiRen 3970647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3971647b3cdcSGeorge Liu { 39720fda0f12SGeorge Liu BMCWEB_ROUTE( 39730fda0f12SGeorge Liu app, 397422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3975647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3976647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 397745ca1b86SEd Tanous [&app](const crow::Request& req, 3978647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 397922d268cbSEd Tanous const std::string& systemName, 3980647b3cdcSGeorge Liu const std::string& postCodeID) { 39813ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 398245ca1b86SEd Tanous { 398345ca1b86SEd Tanous return; 398445ca1b86SEd Tanous } 398572e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 398699351cd8SEd Tanous req.getHeaderValue("Accept"), 39874a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3988647b3cdcSGeorge Liu { 3989002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3990647b3cdcSGeorge Liu return; 3991647b3cdcSGeorge Liu } 399222d268cbSEd Tanous if (systemName != "system") 399322d268cbSEd Tanous { 399422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 399522d268cbSEd Tanous systemName); 399622d268cbSEd Tanous return; 399722d268cbSEd Tanous } 3998647b3cdcSGeorge Liu 3999647b3cdcSGeorge Liu uint64_t currentValue = 0; 4000647b3cdcSGeorge Liu uint16_t index = 0; 4001647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4002647b3cdcSGeorge Liu { 4003002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4004647b3cdcSGeorge Liu return; 4005647b3cdcSGeorge Liu } 4006647b3cdcSGeorge Liu 4007647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4008647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 40095e7e2dc5SEd Tanous const boost::system::error_code& ec, 4010002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4011002d39b4SEd Tanous postcodes) { 4012647b3cdcSGeorge Liu if (ec.value() == EBADR) 4013647b3cdcSGeorge Liu { 4014002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4015002d39b4SEd Tanous postCodeID); 4016647b3cdcSGeorge Liu return; 4017647b3cdcSGeorge Liu } 4018647b3cdcSGeorge Liu if (ec) 4019647b3cdcSGeorge Liu { 4020647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 4021647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4022647b3cdcSGeorge Liu return; 4023647b3cdcSGeorge Liu } 4024647b3cdcSGeorge Liu 4025647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4026002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4027647b3cdcSGeorge Liu { 4028a7405d5fSGunnar Mills BMCWEB_LOG_WARNING << "Wrong currentValue value"; 4029002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4030002d39b4SEd Tanous postCodeID); 4031647b3cdcSGeorge Liu return; 4032647b3cdcSGeorge Liu } 4033647b3cdcSGeorge Liu 40349eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 403546ff87baSEd Tanous if (c.empty()) 4036647b3cdcSGeorge Liu { 4037a7405d5fSGunnar Mills BMCWEB_LOG_WARNING << "No found post code data"; 4038002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4039002d39b4SEd Tanous postCodeID); 4040647b3cdcSGeorge Liu return; 4041647b3cdcSGeorge Liu } 404246ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 404346ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 404446ff87baSEd Tanous std::string_view strData(d, c.size()); 4045647b3cdcSGeorge Liu 4046d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4047647b3cdcSGeorge Liu "application/octet-stream"); 4048d9f6c621SEd Tanous asyncResp->res.addHeader( 4049d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4050002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4051647b3cdcSGeorge Liu }, 4052647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4053647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4054002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4055647b3cdcSGeorge Liu }); 4056647b3cdcSGeorge Liu } 4057647b3cdcSGeorge Liu 40587e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4059a3316fc6SZhikuiRen { 40607e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 406122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4062ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40637e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 406445ca1b86SEd Tanous [&app](const crow::Request& req, 40657e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 406622d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40673ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 406845ca1b86SEd Tanous { 406945ca1b86SEd Tanous return; 407045ca1b86SEd Tanous } 407122d268cbSEd Tanous if (systemName != "system") 407222d268cbSEd Tanous { 407322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 407422d268cbSEd Tanous systemName); 407522d268cbSEd Tanous return; 407622d268cbSEd Tanous } 407722d268cbSEd Tanous 40786f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 40797e860f15SJohn Edward Broadbent }); 4080a3316fc6SZhikuiRen } 4081a3316fc6SZhikuiRen 40821da66f75SEd Tanous } // namespace redfish 4083