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> 53*3544d2a7SEd Tanous #include <ranges> 5426702d01SEd Tanous #include <span> 55cd225da8SJason M. Bills #include <string_view> 56abf2add6SEd Tanous #include <variant> 571da66f75SEd Tanous 581da66f75SEd Tanous namespace redfish 591da66f75SEd Tanous { 601da66f75SEd Tanous 6189492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6289492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6389492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6489492a15SPatrick Williams constexpr const char* deleteAllInterface = 655b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6689492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 67424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6889492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 696eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 701da66f75SEd Tanous 718e31778eSAsmitha Karunanithi enum class DumpCreationProgress 728e31778eSAsmitha Karunanithi { 738e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 748e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 758e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 768e31778eSAsmitha Karunanithi }; 778e31778eSAsmitha Karunanithi 78f6150403SJames Feist namespace fs = std::filesystem; 791da66f75SEd Tanous 80cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 81cb92c03bSAndrew Geissler { 82d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 86cb92c03bSAndrew Geissler { 87cb92c03bSAndrew Geissler return "Critical"; 88cb92c03bSAndrew Geissler } 893174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 90d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 91d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 92cb92c03bSAndrew Geissler { 93cb92c03bSAndrew Geissler return "OK"; 94cb92c03bSAndrew Geissler } 953174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 96cb92c03bSAndrew Geissler { 97cb92c03bSAndrew Geissler return "Warning"; 98cb92c03bSAndrew Geissler } 99cb92c03bSAndrew Geissler return ""; 100cb92c03bSAndrew Geissler } 101cb92c03bSAndrew Geissler 1029017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1039017faf2SAbhishek Patel { 1049017faf2SAbhishek Patel std::optional<bool> notifyAction; 1059017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1069017faf2SAbhishek Patel { 1079017faf2SAbhishek Patel notifyAction = true; 1089017faf2SAbhishek Patel } 1099017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1109017faf2SAbhishek Patel { 1119017faf2SAbhishek Patel notifyAction = false; 1129017faf2SAbhishek Patel } 1139017faf2SAbhishek Patel 1149017faf2SAbhishek Patel return notifyAction; 1159017faf2SAbhishek Patel } 1169017faf2SAbhishek Patel 1177e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 11826ccae32SEd Tanous std::string_view field, 11939e77504SEd Tanous std::string_view& contents) 12016428a1aSJason M. Bills { 12116428a1aSJason M. Bills const char* data = nullptr; 12216428a1aSJason M. Bills size_t length = 0; 12316428a1aSJason M. Bills int ret = 0; 12416428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 12546ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 12646ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 12746ff87baSEd Tanous 12846ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 12916428a1aSJason M. Bills if (ret < 0) 13016428a1aSJason M. Bills { 13116428a1aSJason M. Bills return ret; 13216428a1aSJason M. Bills } 13339e77504SEd Tanous contents = std::string_view(data, length); 13416428a1aSJason M. Bills // Only use the content after the "=" character. 13581ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 13616428a1aSJason M. Bills return ret; 13716428a1aSJason M. Bills } 13816428a1aSJason M. Bills 1397e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 14026ccae32SEd Tanous std::string_view field, const int& base, 14126ccae32SEd Tanous long int& contents) 14216428a1aSJason M. Bills { 14316428a1aSJason M. Bills int ret = 0; 14439e77504SEd Tanous std::string_view metadata; 14516428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14616428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 14716428a1aSJason M. Bills if (ret < 0) 14816428a1aSJason M. Bills { 14916428a1aSJason M. Bills return ret; 15016428a1aSJason M. Bills } 151b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15216428a1aSJason M. Bills return ret; 15316428a1aSJason M. Bills } 15416428a1aSJason M. Bills 1557e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1567e860f15SJohn Edward Broadbent std::string& entryTimestamp) 157a3316fc6SZhikuiRen { 158a3316fc6SZhikuiRen int ret = 0; 159a3316fc6SZhikuiRen uint64_t timestamp = 0; 160a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 161a3316fc6SZhikuiRen if (ret < 0) 162a3316fc6SZhikuiRen { 16362598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 164a3316fc6SZhikuiRen return false; 165a3316fc6SZhikuiRen } 166e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1679c620e21SAsmitha Karunanithi return true; 168a3316fc6SZhikuiRen } 16950b8a43aSEd Tanous 1707e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 171e85d6b16SJason M. Bills const bool firstEntry = true) 17216428a1aSJason M. Bills { 17316428a1aSJason M. Bills int ret = 0; 17416428a1aSJason M. Bills static uint64_t prevTs = 0; 17516428a1aSJason M. Bills static int index = 0; 176e85d6b16SJason M. Bills if (firstEntry) 177e85d6b16SJason M. Bills { 178e85d6b16SJason M. Bills prevTs = 0; 179e85d6b16SJason M. Bills } 180e85d6b16SJason M. Bills 18116428a1aSJason M. Bills // Get the entry timestamp 18216428a1aSJason M. Bills uint64_t curTs = 0; 18316428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 18416428a1aSJason M. Bills if (ret < 0) 18516428a1aSJason M. Bills { 18662598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 18716428a1aSJason M. Bills return false; 18816428a1aSJason M. Bills } 18916428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 19016428a1aSJason M. Bills if (curTs == prevTs) 19116428a1aSJason M. Bills { 19216428a1aSJason M. Bills index++; 19316428a1aSJason M. Bills } 19416428a1aSJason M. Bills else 19516428a1aSJason M. Bills { 19616428a1aSJason M. Bills // Otherwise, reset it 19716428a1aSJason M. Bills index = 0; 19816428a1aSJason M. Bills } 19916428a1aSJason M. Bills // Save the timestamp 20016428a1aSJason M. Bills prevTs = curTs; 20116428a1aSJason M. Bills 20216428a1aSJason M. Bills entryID = std::to_string(curTs); 20316428a1aSJason M. Bills if (index > 0) 20416428a1aSJason M. Bills { 20516428a1aSJason M. Bills entryID += "_" + std::to_string(index); 20616428a1aSJason M. Bills } 20716428a1aSJason M. Bills return true; 20816428a1aSJason M. Bills } 20916428a1aSJason M. Bills 210e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 211e85d6b16SJason M. Bills const bool firstEntry = true) 21295820184SJason M. Bills { 213271584abSEd Tanous static time_t prevTs = 0; 21495820184SJason M. Bills static int index = 0; 215e85d6b16SJason M. Bills if (firstEntry) 216e85d6b16SJason M. Bills { 217e85d6b16SJason M. Bills prevTs = 0; 218e85d6b16SJason M. Bills } 219e85d6b16SJason M. Bills 22095820184SJason M. Bills // Get the entry timestamp 221271584abSEd Tanous std::time_t curTs = 0; 22295820184SJason M. Bills std::tm timeStruct = {}; 22395820184SJason M. Bills std::istringstream entryStream(logEntry); 22495820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 22595820184SJason M. Bills { 22695820184SJason M. Bills curTs = std::mktime(&timeStruct); 22795820184SJason M. Bills } 22895820184SJason M. Bills // If the timestamp isn't unique, increment the index 22995820184SJason M. Bills if (curTs == prevTs) 23095820184SJason M. Bills { 23195820184SJason M. Bills index++; 23295820184SJason M. Bills } 23395820184SJason M. Bills else 23495820184SJason M. Bills { 23595820184SJason M. Bills // Otherwise, reset it 23695820184SJason M. Bills index = 0; 23795820184SJason M. Bills } 23895820184SJason M. Bills // Save the timestamp 23995820184SJason M. Bills prevTs = curTs; 24095820184SJason M. Bills 24195820184SJason M. Bills entryID = std::to_string(curTs); 24295820184SJason M. Bills if (index > 0) 24395820184SJason M. Bills { 24495820184SJason M. Bills entryID += "_" + std::to_string(index); 24595820184SJason M. Bills } 24695820184SJason M. Bills return true; 24795820184SJason M. Bills } 24895820184SJason M. Bills 2497e860f15SJohn Edward Broadbent inline static bool 2508d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2518d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2528d1b46d7Szhanghch05 uint64_t& index) 25316428a1aSJason M. Bills { 25416428a1aSJason M. Bills if (entryID.empty()) 25516428a1aSJason M. Bills { 25616428a1aSJason M. Bills return false; 25716428a1aSJason M. Bills } 25816428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 25939e77504SEd Tanous std::string_view tsStr(entryID); 26016428a1aSJason M. Bills 26181ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 26271d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 26316428a1aSJason M. Bills { 26416428a1aSJason M. Bills // Timestamp has an index 26516428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 26639e77504SEd Tanous std::string_view indexStr(entryID); 26716428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 26884396af9SPatrick Williams auto [ptr, ec] = std::from_chars(indexStr.begin(), indexStr.end(), 26984396af9SPatrick Williams index); 270c0bd5e4bSEd Tanous if (ec != std::errc()) 27116428a1aSJason M. Bills { 2729db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 27316428a1aSJason M. Bills return false; 27416428a1aSJason M. Bills } 27516428a1aSJason M. Bills } 27616428a1aSJason M. Bills // Timestamp has no index 27784396af9SPatrick Williams auto [ptr, ec] = std::from_chars(tsStr.begin(), tsStr.end(), timestamp); 278c0bd5e4bSEd Tanous if (ec != std::errc()) 27916428a1aSJason M. Bills { 2809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 28116428a1aSJason M. Bills return false; 28216428a1aSJason M. Bills } 28316428a1aSJason M. Bills return true; 28416428a1aSJason M. Bills } 28516428a1aSJason M. Bills 28695820184SJason M. Bills static bool 28795820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 28895820184SJason M. Bills { 28995820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 29095820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 29195820184SJason M. Bills 29295820184SJason M. Bills // Loop through the directory looking for redfish log files 29395820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 29495820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 29595820184SJason M. Bills { 29695820184SJason M. Bills // If we find a redfish log file, save the path 29795820184SJason M. Bills std::string filename = dirEnt.path().filename(); 29811ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 29995820184SJason M. Bills { 30095820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 30195820184SJason M. Bills } 30295820184SJason M. Bills } 30395820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 30495820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 30595820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 306*3544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 30795820184SJason M. Bills 30895820184SJason M. Bills return !redfishLogFiles.empty(); 30995820184SJason M. Bills } 31095820184SJason M. Bills 31168dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 31268dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 31368dd075aSAsmitha Karunanithi { 31468dd075aSAsmitha Karunanithi if (originatorType == 31568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 31668dd075aSAsmitha Karunanithi { 31768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 31868dd075aSAsmitha Karunanithi } 31968dd075aSAsmitha Karunanithi if (originatorType == 32068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 32168dd075aSAsmitha Karunanithi { 32268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 32368dd075aSAsmitha Karunanithi } 32468dd075aSAsmitha Karunanithi if (originatorType == 32568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 32668dd075aSAsmitha Karunanithi { 32768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 32868dd075aSAsmitha Karunanithi } 32968dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 33068dd075aSAsmitha Karunanithi } 33168dd075aSAsmitha Karunanithi 332aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3332d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 334c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 33568dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 336aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 337aefe3786SClaire Weinan { 338aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 339aefe3786SClaire Weinan { 340aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 341aefe3786SClaire Weinan { 342aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 343aefe3786SClaire Weinan { 344aefe3786SClaire Weinan if (propertyMap.first == "Status") 345aefe3786SClaire Weinan { 346aefe3786SClaire Weinan const auto* status = 347aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 348aefe3786SClaire Weinan if (status == nullptr) 349aefe3786SClaire Weinan { 350aefe3786SClaire Weinan messages::internalError(asyncResp->res); 351aefe3786SClaire Weinan break; 352aefe3786SClaire Weinan } 353aefe3786SClaire Weinan dumpStatus = *status; 354aefe3786SClaire Weinan } 355aefe3786SClaire Weinan } 356aefe3786SClaire Weinan } 357aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 358aefe3786SClaire Weinan { 359aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 360aefe3786SClaire Weinan { 361aefe3786SClaire Weinan if (propertyMap.first == "Size") 362aefe3786SClaire Weinan { 363aefe3786SClaire Weinan const auto* sizePtr = 364aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 365aefe3786SClaire Weinan if (sizePtr == nullptr) 366aefe3786SClaire Weinan { 367aefe3786SClaire Weinan messages::internalError(asyncResp->res); 368aefe3786SClaire Weinan break; 369aefe3786SClaire Weinan } 370aefe3786SClaire Weinan size = *sizePtr; 371aefe3786SClaire Weinan break; 372aefe3786SClaire Weinan } 373aefe3786SClaire Weinan } 374aefe3786SClaire Weinan } 375aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 376aefe3786SClaire Weinan { 377aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 378aefe3786SClaire Weinan { 379aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 380aefe3786SClaire Weinan { 381aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 382aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 383aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan messages::internalError(asyncResp->res); 386aefe3786SClaire Weinan break; 387aefe3786SClaire Weinan } 388c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 389aefe3786SClaire Weinan break; 390aefe3786SClaire Weinan } 391aefe3786SClaire Weinan } 392aefe3786SClaire Weinan } 39368dd075aSAsmitha Karunanithi else if (interfaceMap.first == 39468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 39568dd075aSAsmitha Karunanithi { 39668dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 39768dd075aSAsmitha Karunanithi { 39868dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 39968dd075aSAsmitha Karunanithi { 40068dd075aSAsmitha Karunanithi const std::string* id = 40168dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 40268dd075aSAsmitha Karunanithi if (id == nullptr) 40368dd075aSAsmitha Karunanithi { 40468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 40568dd075aSAsmitha Karunanithi break; 40668dd075aSAsmitha Karunanithi } 40768dd075aSAsmitha Karunanithi originatorId = *id; 40868dd075aSAsmitha Karunanithi } 40968dd075aSAsmitha Karunanithi 41068dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 41168dd075aSAsmitha Karunanithi { 41268dd075aSAsmitha Karunanithi const std::string* type = 41368dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 41468dd075aSAsmitha Karunanithi if (type == nullptr) 41568dd075aSAsmitha Karunanithi { 41668dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 41768dd075aSAsmitha Karunanithi break; 41868dd075aSAsmitha Karunanithi } 41968dd075aSAsmitha Karunanithi 42068dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 42168dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 42268dd075aSAsmitha Karunanithi { 42368dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 42468dd075aSAsmitha Karunanithi break; 42568dd075aSAsmitha Karunanithi } 42668dd075aSAsmitha Karunanithi } 42768dd075aSAsmitha Karunanithi } 42868dd075aSAsmitha Karunanithi } 429aefe3786SClaire Weinan } 430aefe3786SClaire Weinan } 431aefe3786SClaire Weinan 43221ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 433fdd26906SClaire Weinan { 434fdd26906SClaire Weinan std::string entriesPath; 435fdd26906SClaire Weinan 436fdd26906SClaire Weinan if (dumpType == "BMC") 437fdd26906SClaire Weinan { 438fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 439fdd26906SClaire Weinan } 440fdd26906SClaire Weinan else if (dumpType == "FaultLog") 441fdd26906SClaire Weinan { 442fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 443fdd26906SClaire Weinan } 444fdd26906SClaire Weinan else if (dumpType == "System") 445fdd26906SClaire Weinan { 446fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 447fdd26906SClaire Weinan } 448fdd26906SClaire Weinan else 449fdd26906SClaire Weinan { 45062598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 45162598e31SEd Tanous dumpType); 452fdd26906SClaire Weinan } 453fdd26906SClaire Weinan 454fdd26906SClaire Weinan // Returns empty string on error 455fdd26906SClaire Weinan return entriesPath; 456fdd26906SClaire Weinan } 457fdd26906SClaire Weinan 4588d1b46d7Szhanghch05 inline void 4598d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4605cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4615cb1dd27SAsmitha Karunanithi { 462fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 463fdd26906SClaire Weinan if (entriesPath.empty()) 4645cb1dd27SAsmitha Karunanithi { 4655cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4665cb1dd27SAsmitha Karunanithi return; 4675cb1dd27SAsmitha Karunanithi } 4685cb1dd27SAsmitha Karunanithi 4695eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 4705eb468daSGeorge Liu dbus::utility::getManagedObjects( 4715eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 472fdd26906SClaire Weinan [asyncResp, entriesPath, 4735e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 4745eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 4755cb1dd27SAsmitha Karunanithi if (ec) 4765cb1dd27SAsmitha Karunanithi { 47762598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 4785cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4795cb1dd27SAsmitha Karunanithi return; 4805cb1dd27SAsmitha Karunanithi } 4815cb1dd27SAsmitha Karunanithi 482fdd26906SClaire Weinan // Remove ending slash 483fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 484fdd26906SClaire Weinan if (!odataIdStr.empty()) 485fdd26906SClaire Weinan { 486fdd26906SClaire Weinan odataIdStr.pop_back(); 487fdd26906SClaire Weinan } 488fdd26906SClaire Weinan 489fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 490fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 491fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 492fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 49389492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 49489492a15SPatrick Williams " Dump Entries"; 495fdd26906SClaire Weinan 496*3544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 497b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 498b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 499002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 5005cb1dd27SAsmitha Karunanithi 5015eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 502*3544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 503002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 504002d39b4SEd Tanous r.first.filename()); 505565dfb6fSClaire Weinan }); 506565dfb6fSClaire Weinan 5075cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5085cb1dd27SAsmitha Karunanithi { 509b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5105cb1dd27SAsmitha Karunanithi { 5115cb1dd27SAsmitha Karunanithi continue; 5125cb1dd27SAsmitha Karunanithi } 513c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5145cb1dd27SAsmitha Karunanithi uint64_t size = 0; 51535440d18SAsmitha Karunanithi std::string dumpStatus; 51668dd075aSAsmitha Karunanithi std::string originatorId; 51768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 51868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 519433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5202dfd18efSEd Tanous 5212dfd18efSEd Tanous std::string entryID = object.first.filename(); 5222dfd18efSEd Tanous if (entryID.empty()) 5235cb1dd27SAsmitha Karunanithi { 5245cb1dd27SAsmitha Karunanithi continue; 5255cb1dd27SAsmitha Karunanithi } 5265cb1dd27SAsmitha Karunanithi 527c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 52868dd075aSAsmitha Karunanithi originatorId, originatorType, 529aefe3786SClaire Weinan asyncResp); 5305cb1dd27SAsmitha Karunanithi 5310fda0f12SGeorge Liu if (dumpStatus != 5320fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 53335440d18SAsmitha Karunanithi !dumpStatus.empty()) 53435440d18SAsmitha Karunanithi { 53535440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 53635440d18SAsmitha Karunanithi continue; 53735440d18SAsmitha Karunanithi } 53835440d18SAsmitha Karunanithi 53968dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 540fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5415cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5425cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5435cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 544bbd80db8SClaire Weinan thisEntry["Created"] = 545bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5465cb1dd27SAsmitha Karunanithi 54768dd075aSAsmitha Karunanithi if (!originatorId.empty()) 54868dd075aSAsmitha Karunanithi { 54968dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 55068dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 55168dd075aSAsmitha Karunanithi } 55268dd075aSAsmitha Karunanithi 5535cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5545cb1dd27SAsmitha Karunanithi { 555d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 55689492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 55789492a15SPatrick Williams "/attachment"; 558fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5595cb1dd27SAsmitha Karunanithi } 5605cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5615cb1dd27SAsmitha Karunanithi { 562d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 563d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 56489492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 56589492a15SPatrick Williams "/attachment"; 566fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5675cb1dd27SAsmitha Karunanithi } 568b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 5695cb1dd27SAsmitha Karunanithi } 570002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 571*3544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 5725eb468daSGeorge Liu }); 5735cb1dd27SAsmitha Karunanithi } 5745cb1dd27SAsmitha Karunanithi 5758d1b46d7Szhanghch05 inline void 576c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5778d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5785cb1dd27SAsmitha Karunanithi { 579fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 580fdd26906SClaire Weinan if (entriesPath.empty()) 5815cb1dd27SAsmitha Karunanithi { 5825cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5835cb1dd27SAsmitha Karunanithi return; 5845cb1dd27SAsmitha Karunanithi } 5855cb1dd27SAsmitha Karunanithi 5865eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5875eb468daSGeorge Liu dbus::utility::getManagedObjects( 5885eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 589fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 5905e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 59102cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5925cb1dd27SAsmitha Karunanithi if (ec) 5935cb1dd27SAsmitha Karunanithi { 59462598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5955cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5965cb1dd27SAsmitha Karunanithi return; 5975cb1dd27SAsmitha Karunanithi } 5985cb1dd27SAsmitha Karunanithi 599b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 600b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 601b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 602002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 603b47452b2SAsmitha Karunanithi 6049eb808c1SEd Tanous for (const auto& objectPath : resp) 6055cb1dd27SAsmitha Karunanithi { 606b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6075cb1dd27SAsmitha Karunanithi { 6085cb1dd27SAsmitha Karunanithi continue; 6095cb1dd27SAsmitha Karunanithi } 6105cb1dd27SAsmitha Karunanithi 6115cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 612c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6135cb1dd27SAsmitha Karunanithi uint64_t size = 0; 61435440d18SAsmitha Karunanithi std::string dumpStatus; 61568dd075aSAsmitha Karunanithi std::string originatorId; 61668dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 61768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6185cb1dd27SAsmitha Karunanithi 619aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 62068dd075aSAsmitha Karunanithi timestampUs, originatorId, 62168dd075aSAsmitha Karunanithi originatorType, asyncResp); 6225cb1dd27SAsmitha Karunanithi 6230fda0f12SGeorge Liu if (dumpStatus != 6240fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 62535440d18SAsmitha Karunanithi !dumpStatus.empty()) 62635440d18SAsmitha Karunanithi { 62735440d18SAsmitha Karunanithi // Dump status is not Complete 62835440d18SAsmitha Karunanithi // return not found until status is changed to Completed 629d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 630d1bde9e5SKrzysztof Grobelny entryID); 63135440d18SAsmitha Karunanithi return; 63235440d18SAsmitha Karunanithi } 63335440d18SAsmitha Karunanithi 6345cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 63568dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 636fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6375cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6385cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6395cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 640bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 641bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6425cb1dd27SAsmitha Karunanithi 64368dd075aSAsmitha Karunanithi if (!originatorId.empty()) 64468dd075aSAsmitha Karunanithi { 64568dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 64668dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 64768dd075aSAsmitha Karunanithi } 64868dd075aSAsmitha Karunanithi 6495cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6505cb1dd27SAsmitha Karunanithi { 651d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 652d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 653fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 654fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6555cb1dd27SAsmitha Karunanithi } 6565cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6575cb1dd27SAsmitha Karunanithi { 658d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 659002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 660d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 661fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 662fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6635cb1dd27SAsmitha Karunanithi } 6645cb1dd27SAsmitha Karunanithi } 665e05aec50SEd Tanous if (!foundDumpEntry) 666b47452b2SAsmitha Karunanithi { 66762598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 668b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 669b90d14f2SMyung Bae entryID); 670b47452b2SAsmitha Karunanithi return; 671b47452b2SAsmitha Karunanithi } 6725eb468daSGeorge Liu }); 6735cb1dd27SAsmitha Karunanithi } 6745cb1dd27SAsmitha Karunanithi 6758d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6769878256fSStanley Chu const std::string& entryID, 677b47452b2SAsmitha Karunanithi const std::string& dumpType) 6785cb1dd27SAsmitha Karunanithi { 679002d39b4SEd Tanous auto respHandler = 6805e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 68162598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 6825cb1dd27SAsmitha Karunanithi if (ec) 6835cb1dd27SAsmitha Karunanithi { 6843de8d8baSGeorge Liu if (ec.value() == EBADR) 6853de8d8baSGeorge Liu { 6863de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6873de8d8baSGeorge Liu return; 6883de8d8baSGeorge Liu } 68962598e31SEd Tanous BMCWEB_LOG_ERROR( 69062598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 69162598e31SEd Tanous entryID); 6925cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6935cb1dd27SAsmitha Karunanithi return; 6945cb1dd27SAsmitha Karunanithi } 6955cb1dd27SAsmitha Karunanithi }; 6965cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6975cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 698b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 699b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 700b47452b2SAsmitha Karunanithi entryID, 7015cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7025cb1dd27SAsmitha Karunanithi } 7035cb1dd27SAsmitha Karunanithi 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 { 73162598e31SEd Tanous 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 { 76562598e31SEd Tanous 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 { 77762598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 77862598e31SEd Tanous 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 { 79362598e31SEd Tanous 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]( 8218b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 822a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 8238b24275dSEd Tanous if (ec2) 824cb13a392SEd Tanous { 82562598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 82662598e31SEd Tanous createdObjPath.str); 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 { 84262598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 84362598e31SEd Tanous createdObjPath.str); 8448e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8458e31778eSAsmitha Karunanithi return task::completed; 8468e31778eSAsmitha Karunanithi } 8478e31778eSAsmitha Karunanithi 8488e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8498e31778eSAsmitha Karunanithi { 85062598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 85162598e31SEd Tanous createdObjPath.str); 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 86762598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 86862598e31SEd Tanous createdObjPath.str); 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 { 91062598e31SEd Tanous BMCWEB_LOG_ERROR( 91162598e31SEd Tanous "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 { 92062598e31SEd Tanous 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 { 93062598e31SEd Tanous BMCWEB_LOG_ERROR( 93162598e31SEd Tanous "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 { 93862598e31SEd Tanous BMCWEB_LOG_ERROR( 93962598e31SEd Tanous "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 { 94762598e31SEd Tanous 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 { 97262598e31SEd Tanous 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 98062598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 98162598e31SEd Tanous dbusError->name, 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 } 101362598e31SEd Tanous 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 { 103262598e31SEd Tanous 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 } 10917f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 10927f3e84a1SEd Tanous { 10937f3e84a1SEd Tanous // Option currently returns no systems. TBD 10947f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 10957f3e84a1SEd Tanous systemName); 10967f3e84a1SEd Tanous return; 10977f3e84a1SEd Tanous } 109822d268cbSEd Tanous if (systemName != "system") 109922d268cbSEd Tanous { 110022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 110122d268cbSEd Tanous systemName); 110222d268cbSEd Tanous return; 110322d268cbSEd Tanous } 110422d268cbSEd Tanous 11057e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 11067e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1107c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1108c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1109c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1110029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 111145ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1112c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1113c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1114002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1115c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11161476687dSEd Tanous nlohmann::json::object_t eventLog; 11171476687dSEd Tanous eventLog["@odata.id"] = 11181476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1119b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 11205cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 11211476687dSEd Tanous nlohmann::json::object_t dumpLog; 1122002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1123b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1124c9bb6861Sraviteja-b #endif 1125c9bb6861Sraviteja-b 1126d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 11271476687dSEd Tanous nlohmann::json::object_t crashdump; 11281476687dSEd Tanous crashdump["@odata.id"] = 11291476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1130b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1131d53dd41fSJason M. Bills #endif 1132b7028ebfSSpencer Ku 1133b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 11341476687dSEd Tanous nlohmann::json::object_t hostlogger; 11351476687dSEd Tanous hostlogger["@odata.id"] = 11361476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1137b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1138b7028ebfSSpencer Ku #endif 1139c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1140c4bf6374SJason M. Bills logServiceArray.size(); 1141a3316fc6SZhikuiRen 11427a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11437a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11447a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11457a1dbc48SGeorge Liu "/", 0, interfaces, 11467a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1147b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1148b9d36b47SEd Tanous subtreePath) { 1149a3316fc6SZhikuiRen if (ec) 1150a3316fc6SZhikuiRen { 115162598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1152a3316fc6SZhikuiRen return; 1153a3316fc6SZhikuiRen } 1154a3316fc6SZhikuiRen 115555f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1156a3316fc6SZhikuiRen { 1157a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1158a3316fc6SZhikuiRen { 115923a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1160a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1161613dabeaSEd Tanous nlohmann::json::object_t member; 1162613dabeaSEd Tanous member["@odata.id"] = 1163613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1164613dabeaSEd Tanous 1165b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1166613dabeaSEd Tanous 116745ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 116823a21a1cSEd Tanous logServiceArrayLocal.size(); 1169a3316fc6SZhikuiRen return; 1170a3316fc6SZhikuiRen } 1171a3316fc6SZhikuiRen } 11727a1dbc48SGeorge Liu }); 11737e860f15SJohn Edward Broadbent }); 1174c4bf6374SJason M. Bills } 1175c4bf6374SJason M. Bills 11767e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1177c4bf6374SJason M. Bills { 117822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1179ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1180002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1181002d39b4SEd Tanous [&app](const crow::Request& req, 118222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 118322d268cbSEd Tanous const std::string& systemName) { 11843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 118545ca1b86SEd Tanous { 118645ca1b86SEd Tanous return; 118745ca1b86SEd Tanous } 118822d268cbSEd Tanous if (systemName != "system") 118922d268cbSEd Tanous { 119022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 119122d268cbSEd Tanous systemName); 119222d268cbSEd Tanous return; 119322d268cbSEd Tanous } 1194c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1195029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1196c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1197c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1198c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1199002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1200c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1201c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 12027c8c4058STejas Patil 12037c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 12042b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 12057c8c4058STejas Patil 12067c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 12077c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 12087c8c4058STejas Patil redfishDateTimeOffset.second; 12097c8c4058STejas Patil 12101476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 12111476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1212e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1213e7d6c8b2SGunnar Mills 12140fda0f12SGeorge Liu {"target", 12150fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 12167e860f15SJohn Edward Broadbent }); 1217489640c6SJason M. Bills } 1218489640c6SJason M. Bills 12197e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1220489640c6SJason M. Bills { 12214978b63fSJason M. Bills BMCWEB_ROUTE( 12224978b63fSJason M. Bills app, 122322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1224432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 12257e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 122645ca1b86SEd Tanous [&app](const crow::Request& req, 122722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 122822d268cbSEd Tanous const std::string& systemName) { 12293ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 123045ca1b86SEd Tanous { 123145ca1b86SEd Tanous return; 123245ca1b86SEd Tanous } 123322d268cbSEd Tanous if (systemName != "system") 123422d268cbSEd Tanous { 123522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 123622d268cbSEd Tanous systemName); 123722d268cbSEd Tanous return; 123822d268cbSEd Tanous } 1239489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1240489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1241489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1242489640c6SJason M. Bills { 1243489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1244489640c6SJason M. Bills { 1245489640c6SJason M. Bills std::error_code ec; 1246489640c6SJason M. Bills std::filesystem::remove(file, ec); 1247489640c6SJason M. Bills } 1248489640c6SJason M. Bills } 1249489640c6SJason M. Bills 1250489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1251489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 12525e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1253489640c6SJason M. Bills if (ec) 1254489640c6SJason M. Bills { 125562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1256489640c6SJason M. Bills messages::internalError(asyncResp->res); 1257489640c6SJason M. Bills return; 1258489640c6SJason M. Bills } 1259489640c6SJason M. Bills 1260489640c6SJason M. Bills messages::success(asyncResp->res); 1261489640c6SJason M. Bills }, 1262489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1263002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1264002d39b4SEd Tanous "replace"); 12657e860f15SJohn Edward Broadbent }); 1266c4bf6374SJason M. Bills } 1267c4bf6374SJason M. Bills 1268ac992cdeSJason M. Bills enum class LogParseError 1269ac992cdeSJason M. Bills { 1270ac992cdeSJason M. Bills success, 1271ac992cdeSJason M. Bills parseFailed, 1272ac992cdeSJason M. Bills messageIdNotInRegistry, 1273ac992cdeSJason M. Bills }; 1274ac992cdeSJason M. Bills 1275ac992cdeSJason M. Bills static LogParseError 1276ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1277b5a76932SEd Tanous const std::string& logEntry, 1278de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1279c4bf6374SJason M. Bills { 128095820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1281cd225da8SJason M. Bills // First get the Timestamp 1282f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1283cd225da8SJason M. Bills if (space == std::string::npos) 128495820184SJason M. Bills { 1285ac992cdeSJason M. Bills return LogParseError::parseFailed; 128695820184SJason M. Bills } 1287cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1288cd225da8SJason M. Bills // Then get the log contents 1289f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1290cd225da8SJason M. Bills if (entryStart == std::string::npos) 1291cd225da8SJason M. Bills { 1292ac992cdeSJason M. Bills return LogParseError::parseFailed; 1293cd225da8SJason M. Bills } 1294cd225da8SJason M. Bills std::string_view entry(logEntry); 1295cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1296cd225da8SJason M. Bills // Use split to separate the entry into its fields 1297cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 129850ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1299cd225da8SJason M. Bills // We need at least a MessageId to be valid 13001e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 13011e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1302cd225da8SJason M. Bills { 1303ac992cdeSJason M. Bills return LogParseError::parseFailed; 1304cd225da8SJason M. Bills } 13051e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 13064851d45dSJason M. Bills // Get the Message from the MessageRegistry 1307fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1308c4bf6374SJason M. Bills 13091e6deaf6SEd Tanous logEntryIter++; 131054417b02SSui Chen if (message == nullptr) 1311c4bf6374SJason M. Bills { 131262598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1313ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1314c4bf6374SJason M. Bills } 1315c4bf6374SJason M. Bills 13161e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 13171e6deaf6SEd Tanous logEntryFields.end()); 1318c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1319c05bba45SEd Tanous 13201e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 13211e6deaf6SEd Tanous message->message); 13221e6deaf6SEd Tanous if (msg.empty()) 132315a86ff6SJason M. Bills { 13241e6deaf6SEd Tanous return LogParseError::parseFailed; 132515a86ff6SJason M. Bills } 13264851d45dSJason M. Bills 132795820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 132895820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 132995820184SJason M. Bills // between the '.' and the '+', so just remove them. 1330f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1331f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 133295820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1333c4bf6374SJason M. Bills { 133495820184SJason M. Bills timestamp.erase(dot, plus - dot); 1335c4bf6374SJason M. Bills } 1336c4bf6374SJason M. Bills 1337c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13389c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1339ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1340ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1341ef4c65b7SEd Tanous logEntryID); 134284afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 134384afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 134484afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 134584afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 134684afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 134784afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 134884afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 134984afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1350ac992cdeSJason M. Bills return LogParseError::success; 1351c4bf6374SJason M. Bills } 1352c4bf6374SJason M. Bills 13537e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1354c4bf6374SJason M. Bills { 135522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13568b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1357002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1358002d39b4SEd Tanous [&app](const crow::Request& req, 135922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 136022d268cbSEd Tanous const std::string& systemName) { 1361c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1362c937d2bfSEd Tanous .canDelegateTop = true, 1363c937d2bfSEd Tanous .canDelegateSkip = true, 1364c937d2bfSEd Tanous }; 1365c937d2bfSEd Tanous query_param::Query delegatedQuery; 1366c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13673ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1368c4bf6374SJason M. Bills { 1369c4bf6374SJason M. Bills return; 1370c4bf6374SJason M. Bills } 13717f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 13727f3e84a1SEd Tanous { 13737f3e84a1SEd Tanous // Option currently returns no systems. TBD 13747f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 13757f3e84a1SEd Tanous systemName); 13767f3e84a1SEd Tanous return; 13777f3e84a1SEd Tanous } 137822d268cbSEd Tanous if (systemName != "system") 137922d268cbSEd Tanous { 138022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 138122d268cbSEd Tanous systemName); 138222d268cbSEd Tanous return; 138322d268cbSEd Tanous } 138422d268cbSEd Tanous 13855143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13863648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13873648c8beSEd Tanous 13887e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13897e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1390c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1391c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1392c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1393029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1394c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1395c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1396c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1397cb92c03bSAndrew Geissler 13984978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1399c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 14007e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 14017e860f15SJohn Edward Broadbent // entry 140295820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 140395820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1404b01bf299SEd Tanous uint64_t entryCount = 0; 1405cd225da8SJason M. Bills std::string logEntry; 140695820184SJason M. Bills 14077e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14087e860f15SJohn Edward Broadbent // backwards 1409002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1410002d39b4SEd Tanous it++) 1411c4bf6374SJason M. Bills { 1412cd225da8SJason M. Bills std::ifstream logStream(*it); 141395820184SJason M. Bills if (!logStream.is_open()) 1414c4bf6374SJason M. Bills { 1415c4bf6374SJason M. Bills continue; 1416c4bf6374SJason M. Bills } 1417c4bf6374SJason M. Bills 1418e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1419e85d6b16SJason M. Bills bool firstEntry = true; 142095820184SJason M. Bills while (std::getline(logStream, logEntry)) 142195820184SJason M. Bills { 1422c4bf6374SJason M. Bills std::string idStr; 1423e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1424c4bf6374SJason M. Bills { 1425c4bf6374SJason M. Bills continue; 1426c4bf6374SJason M. Bills } 1427e85d6b16SJason M. Bills firstEntry = false; 1428e85d6b16SJason M. Bills 1429de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 143089492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 143189492a15SPatrick Williams bmcLogEntry); 1432ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1433ac992cdeSJason M. Bills { 1434ac992cdeSJason M. Bills continue; 1435ac992cdeSJason M. Bills } 1436ac992cdeSJason M. Bills if (status != LogParseError::success) 1437c4bf6374SJason M. Bills { 1438c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1439c4bf6374SJason M. Bills return; 1440c4bf6374SJason M. Bills } 1441de703c5dSJason M. Bills 1442de703c5dSJason M. Bills entryCount++; 1443de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1444de703c5dSJason M. Bills // start) and top (number of entries to display) 14453648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1446de703c5dSJason M. Bills { 1447de703c5dSJason M. Bills continue; 1448de703c5dSJason M. Bills } 1449de703c5dSJason M. Bills 1450b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1451c4bf6374SJason M. Bills } 145295820184SJason M. Bills } 1453c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14543648c8beSEd Tanous if (skip + top < entryCount) 1455c4bf6374SJason M. Bills { 1456c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14574978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14583648c8beSEd Tanous std::to_string(skip + top); 1459c4bf6374SJason M. Bills } 14607e860f15SJohn Edward Broadbent }); 1461897967deSJason M. Bills } 1462897967deSJason M. Bills 14637e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1464897967deSJason M. Bills { 14657e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 146622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1467ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14687e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 146945ca1b86SEd Tanous [&app](const crow::Request& req, 14707e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 147122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 147345ca1b86SEd Tanous { 147445ca1b86SEd Tanous return; 147545ca1b86SEd Tanous } 14767f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 14777f3e84a1SEd Tanous { 14787f3e84a1SEd Tanous // Option currently returns no systems. TBD 14797f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 14807f3e84a1SEd Tanous systemName); 14817f3e84a1SEd Tanous return; 14827f3e84a1SEd Tanous } 148322d268cbSEd Tanous 148422d268cbSEd Tanous if (systemName != "system") 148522d268cbSEd Tanous { 148622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 148722d268cbSEd Tanous systemName); 148822d268cbSEd Tanous return; 148922d268cbSEd Tanous } 149022d268cbSEd Tanous 14917e860f15SJohn Edward Broadbent const std::string& targetID = param; 14928d1b46d7Szhanghch05 14937e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14947e860f15SJohn Edward Broadbent // entry to find the target entry 1495897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1496897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1497897967deSJason M. Bills std::string logEntry; 1498897967deSJason M. Bills 14997e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15007e860f15SJohn Edward Broadbent // backwards 1501002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1502002d39b4SEd Tanous it++) 1503897967deSJason M. Bills { 1504897967deSJason M. Bills std::ifstream logStream(*it); 1505897967deSJason M. Bills if (!logStream.is_open()) 1506897967deSJason M. Bills { 1507897967deSJason M. Bills continue; 1508897967deSJason M. Bills } 1509897967deSJason M. Bills 1510897967deSJason M. Bills // Reset the unique ID on the first entry 1511897967deSJason M. Bills bool firstEntry = true; 1512897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1513897967deSJason M. Bills { 1514897967deSJason M. Bills std::string idStr; 1515897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1516897967deSJason M. Bills { 1517897967deSJason M. Bills continue; 1518897967deSJason M. Bills } 1519897967deSJason M. Bills firstEntry = false; 1520897967deSJason M. Bills 1521897967deSJason M. Bills if (idStr == targetID) 1522897967deSJason M. Bills { 1523de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1524ac992cdeSJason M. Bills LogParseError status = 1525ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1526ac992cdeSJason M. Bills if (status != LogParseError::success) 1527897967deSJason M. Bills { 1528897967deSJason M. Bills messages::internalError(asyncResp->res); 1529897967deSJason M. Bills return; 1530897967deSJason M. Bills } 1531d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1532897967deSJason M. Bills return; 1533897967deSJason M. Bills } 1534897967deSJason M. Bills } 1535897967deSJason M. Bills } 1536897967deSJason M. Bills // Requested ID was not found 15379db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15387e860f15SJohn Edward Broadbent }); 153908a4e4b5SAnthony Wilson } 154008a4e4b5SAnthony Wilson 15417e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 154208a4e4b5SAnthony Wilson { 154322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1544ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1545002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1546002d39b4SEd Tanous [&app](const crow::Request& req, 154722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 154822d268cbSEd Tanous const std::string& systemName) { 15493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 155045ca1b86SEd Tanous { 155145ca1b86SEd Tanous return; 155245ca1b86SEd Tanous } 15537f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 15547f3e84a1SEd Tanous { 15557f3e84a1SEd Tanous // Option currently returns no systems. TBD 15567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15577f3e84a1SEd Tanous systemName); 15587f3e84a1SEd Tanous return; 15597f3e84a1SEd Tanous } 156022d268cbSEd Tanous if (systemName != "system") 156122d268cbSEd Tanous { 156222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 156322d268cbSEd Tanous systemName); 156422d268cbSEd Tanous return; 156522d268cbSEd Tanous } 156622d268cbSEd Tanous 15677e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15687e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 156908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 157008a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 157108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 157208a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 157308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 157408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 157508a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 157608a4e4b5SAnthony Wilson 1577cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1578cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 15795eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 15805eb468daSGeorge Liu dbus::utility::getManagedObjects( 15815eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 15825e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1583914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1584cb92c03bSAndrew Geissler if (ec) 1585cb92c03bSAndrew Geissler { 1586cb92c03bSAndrew Geissler // TODO Handle for specific error code 158762598e31SEd Tanous BMCWEB_LOG_ERROR( 158862598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1589cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1590cb92c03bSAndrew Geissler return; 1591cb92c03bSAndrew Geissler } 1592*3544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 15939eb808c1SEd Tanous for (const auto& objectPath : resp) 1594cb92c03bSAndrew Geissler { 1595914e2d5dSEd Tanous const uint32_t* id = nullptr; 1596c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1597c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1598914e2d5dSEd Tanous const std::string* severity = nullptr; 1599914e2d5dSEd Tanous const std::string* message = nullptr; 1600914e2d5dSEd Tanous const std::string* filePath = nullptr; 16019c11a172SVijay Lobo const std::string* resolution = nullptr; 160275710de2SXiaochao Ma bool resolved = false; 16039017faf2SAbhishek Patel const std::string* notify = nullptr; 16049017faf2SAbhishek Patel 16059eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1606f86bb901SAdriana Kobylak { 1607f86bb901SAdriana Kobylak if (interfaceMap.first == 1608f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1609f86bb901SAdriana Kobylak { 1610002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1611cb92c03bSAndrew Geissler { 1612cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1613cb92c03bSAndrew Geissler { 1614002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1615cb92c03bSAndrew Geissler } 1616cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1617cb92c03bSAndrew Geissler { 1618002d39b4SEd Tanous timestamp = 1619002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16207e860f15SJohn Edward Broadbent } 1621002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 16227e860f15SJohn Edward Broadbent { 1623002d39b4SEd Tanous updateTimestamp = 1624002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16257e860f15SJohn Edward Broadbent } 16267e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 16277e860f15SJohn Edward Broadbent { 16287e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 16297e860f15SJohn Edward Broadbent &propertyMap.second); 16307e860f15SJohn Edward Broadbent } 16319c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 16329c11a172SVijay Lobo { 16339c11a172SVijay Lobo resolution = std::get_if<std::string>( 16349c11a172SVijay Lobo &propertyMap.second); 16359c11a172SVijay Lobo } 16367e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 16377e860f15SJohn Edward Broadbent { 16387e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 16397e860f15SJohn Edward Broadbent &propertyMap.second); 16407e860f15SJohn Edward Broadbent } 16417e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 16427e860f15SJohn Edward Broadbent { 1643914e2d5dSEd Tanous const bool* resolveptr = 1644002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16457e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16467e860f15SJohn Edward Broadbent { 1647002d39b4SEd Tanous messages::internalError(asyncResp->res); 16487e860f15SJohn Edward Broadbent return; 16497e860f15SJohn Edward Broadbent } 16507e860f15SJohn Edward Broadbent resolved = *resolveptr; 16517e860f15SJohn Edward Broadbent } 16529017faf2SAbhishek Patel else if (propertyMap.first == 16539017faf2SAbhishek Patel "ServiceProviderNotify") 16549017faf2SAbhishek Patel { 16559017faf2SAbhishek Patel notify = std::get_if<std::string>( 16569017faf2SAbhishek Patel &propertyMap.second); 16579017faf2SAbhishek Patel if (notify == nullptr) 16589017faf2SAbhishek Patel { 16599017faf2SAbhishek Patel messages::internalError(asyncResp->res); 16609017faf2SAbhishek Patel return; 16619017faf2SAbhishek Patel } 16629017faf2SAbhishek Patel } 16637e860f15SJohn Edward Broadbent } 16647e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16657e860f15SJohn Edward Broadbent severity == nullptr) 16667e860f15SJohn Edward Broadbent { 16677e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16687e860f15SJohn Edward Broadbent return; 16697e860f15SJohn Edward Broadbent } 16707e860f15SJohn Edward Broadbent } 16717e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16727e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16737e860f15SJohn Edward Broadbent { 1674002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16757e860f15SJohn Edward Broadbent { 16767e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16777e860f15SJohn Edward Broadbent { 16787e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16797e860f15SJohn Edward Broadbent &propertyMap.second); 16807e860f15SJohn Edward Broadbent } 16817e860f15SJohn Edward Broadbent } 16827e860f15SJohn Edward Broadbent } 16837e860f15SJohn Edward Broadbent } 16847e860f15SJohn Edward Broadbent // Object path without the 16857e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16867e860f15SJohn Edward Broadbent // and continue. 16877e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1688c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1689c419c759SEd Tanous updateTimestamp == nullptr) 16907e860f15SJohn Edward Broadbent { 16917e860f15SJohn Edward Broadbent continue; 16927e860f15SJohn Edward Broadbent } 1693*3544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 16949c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1695ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1696ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1697ef4c65b7SEd Tanous std::to_string(*id)); 16987e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16997e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 17007e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 17017e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 17029c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17039c11a172SVijay Lobo { 17049c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 17059c11a172SVijay Lobo } 17069017faf2SAbhishek Patel std::optional<bool> notifyAction = 17079017faf2SAbhishek Patel getProviderNotifyAction(*notify); 17089017faf2SAbhishek Patel if (notifyAction) 17099017faf2SAbhishek Patel { 17109017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 17119017faf2SAbhishek Patel } 17127e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 17137e860f15SJohn Edward Broadbent thisEntry["Severity"] = 17147e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 17157e860f15SJohn Edward Broadbent thisEntry["Created"] = 17162b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 17177e860f15SJohn Edward Broadbent thisEntry["Modified"] = 17182b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 17197e860f15SJohn Edward Broadbent if (filePath != nullptr) 17207e860f15SJohn Edward Broadbent { 17217e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 17220fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 17237e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 17247e860f15SJohn Edward Broadbent } 17257e860f15SJohn Edward Broadbent } 1726*3544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 1727*3544d2a7SEd Tanous const nlohmann::json& right) { 17287e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 17297e860f15SJohn Edward Broadbent }); 17307e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 17317e860f15SJohn Edward Broadbent entriesArray.size(); 1732*3544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 17335eb468daSGeorge Liu }); 17347e860f15SJohn Edward Broadbent }); 17357e860f15SJohn Edward Broadbent } 17367e860f15SJohn Edward Broadbent 17377e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 17387e860f15SJohn Edward Broadbent { 17397e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 174022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1741ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1742002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1743002d39b4SEd Tanous [&app](const crow::Request& req, 17447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17477e860f15SJohn Edward Broadbent { 174845ca1b86SEd Tanous return; 174945ca1b86SEd Tanous } 17507f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 17517f3e84a1SEd Tanous { 17527f3e84a1SEd Tanous // Option currently returns no systems. TBD 17537f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17547f3e84a1SEd Tanous systemName); 17557f3e84a1SEd Tanous return; 17567f3e84a1SEd Tanous } 175722d268cbSEd Tanous if (systemName != "system") 175822d268cbSEd Tanous { 175922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 176022d268cbSEd Tanous systemName); 176122d268cbSEd Tanous return; 176222d268cbSEd Tanous } 176322d268cbSEd Tanous 17647e860f15SJohn Edward Broadbent std::string entryID = param; 17657e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17667e860f15SJohn Edward Broadbent 17677e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17687e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1769d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1770d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1771d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 17725e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1773b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17747e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17757e860f15SJohn Edward Broadbent { 1776d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1777d1bde9e5SKrzysztof Grobelny entryID); 17787e860f15SJohn Edward Broadbent return; 17797e860f15SJohn Edward Broadbent } 17807e860f15SJohn Edward Broadbent if (ec) 17817e860f15SJohn Edward Broadbent { 178262598e31SEd Tanous BMCWEB_LOG_ERROR( 178362598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 17847e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17857e860f15SJohn Edward Broadbent return; 17867e860f15SJohn Edward Broadbent } 1787914e2d5dSEd Tanous const uint32_t* id = nullptr; 1788c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1789c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1790914e2d5dSEd Tanous const std::string* severity = nullptr; 1791914e2d5dSEd Tanous const std::string* message = nullptr; 1792914e2d5dSEd Tanous const std::string* filePath = nullptr; 17939c11a172SVijay Lobo const std::string* resolution = nullptr; 17947e860f15SJohn Edward Broadbent bool resolved = false; 17959017faf2SAbhishek Patel const std::string* notify = nullptr; 17967e860f15SJohn Edward Broadbent 1797d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1798d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1799d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 18009c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 18019017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 18029017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1803d1bde9e5SKrzysztof Grobelny 1804d1bde9e5SKrzysztof Grobelny if (!success) 180575710de2SXiaochao Ma { 180675710de2SXiaochao Ma messages::internalError(asyncResp->res); 180775710de2SXiaochao Ma return; 180875710de2SXiaochao Ma } 1809d1bde9e5SKrzysztof Grobelny 1810002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 18119017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 18129017faf2SAbhishek Patel notify == nullptr) 1813f86bb901SAdriana Kobylak { 1814ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1815271584abSEd Tanous return; 1816271584abSEd Tanous } 18179017faf2SAbhishek Patel 1818f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 18199c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1820ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1821ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1822ef4c65b7SEd Tanous std::to_string(*id)); 182345ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1824f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1825f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1826f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 18279017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 18289017faf2SAbhishek Patel if (notifyAction) 18299017faf2SAbhishek Patel { 18309017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 18319017faf2SAbhishek Patel *notifyAction; 18329017faf2SAbhishek Patel } 18339c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18349c11a172SVijay Lobo { 18359c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 18369c11a172SVijay Lobo } 1837f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1838f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1839f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1840f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 18412b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1842f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 18432b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1844f86bb901SAdriana Kobylak if (filePath != nullptr) 1845f86bb901SAdriana Kobylak { 1846f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1847e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1848e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1849f86bb901SAdriana Kobylak } 1850d1bde9e5SKrzysztof Grobelny }); 18517e860f15SJohn Edward Broadbent }); 1852336e96c6SChicago Duan 18537e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 185422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1855ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18567e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 185745ca1b86SEd Tanous [&app](const crow::Request& req, 18587e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 185922d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 18603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 186145ca1b86SEd Tanous { 186245ca1b86SEd Tanous return; 186345ca1b86SEd Tanous } 18647f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 18657f3e84a1SEd Tanous { 18667f3e84a1SEd Tanous // Option currently returns no systems. TBD 18677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 18687f3e84a1SEd Tanous systemName); 18697f3e84a1SEd Tanous return; 18707f3e84a1SEd Tanous } 187122d268cbSEd Tanous if (systemName != "system") 187222d268cbSEd Tanous { 187322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 187422d268cbSEd Tanous systemName); 187522d268cbSEd Tanous return; 187622d268cbSEd Tanous } 187775710de2SXiaochao Ma std::optional<bool> resolved; 187875710de2SXiaochao Ma 187915ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 18807e860f15SJohn Edward Broadbent resolved)) 188175710de2SXiaochao Ma { 188275710de2SXiaochao Ma return; 188375710de2SXiaochao Ma } 188462598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 188575710de2SXiaochao Ma 18869ae226faSGeorge Liu sdbusplus::asio::setProperty( 18879ae226faSGeorge Liu *crow::connections::systemBus, "xyz.openbmc_project.Logging", 18889ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 18899ae226faSGeorge Liu "xyz.openbmc_project.Logging.Entry", "Resolved", *resolved, 18905e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 189175710de2SXiaochao Ma if (ec) 189275710de2SXiaochao Ma { 189362598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 189475710de2SXiaochao Ma messages::internalError(asyncResp->res); 189575710de2SXiaochao Ma return; 189675710de2SXiaochao Ma } 18979ae226faSGeorge Liu }); 18987e860f15SJohn Edward Broadbent }); 189975710de2SXiaochao Ma 19007e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 190122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1902ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1903ed398213SEd Tanous 1904002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1905002d39b4SEd Tanous [&app](const crow::Request& req, 1906002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 190722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1909336e96c6SChicago Duan { 191045ca1b86SEd Tanous return; 191145ca1b86SEd Tanous } 19127f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19137f3e84a1SEd Tanous { 19147f3e84a1SEd Tanous // Option currently returns no systems. TBD 19157f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19167f3e84a1SEd Tanous systemName); 19177f3e84a1SEd Tanous return; 19187f3e84a1SEd Tanous } 191922d268cbSEd Tanous if (systemName != "system") 192022d268cbSEd Tanous { 192122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 192222d268cbSEd Tanous systemName); 192322d268cbSEd Tanous return; 192422d268cbSEd Tanous } 192562598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 1926336e96c6SChicago Duan 19277e860f15SJohn Edward Broadbent std::string entryID = param; 1928336e96c6SChicago Duan 1929336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1930336e96c6SChicago Duan 1931336e96c6SChicago Duan // Process response from Logging service. 1932002d39b4SEd Tanous auto respHandler = 19335e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 193462598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 1935336e96c6SChicago Duan if (ec) 1936336e96c6SChicago Duan { 19373de8d8baSGeorge Liu if (ec.value() == EBADR) 19383de8d8baSGeorge Liu { 193945ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 194045ca1b86SEd Tanous entryID); 19413de8d8baSGeorge Liu return; 19423de8d8baSGeorge Liu } 1943336e96c6SChicago Duan // TODO Handle for specific error code 194462598e31SEd Tanous BMCWEB_LOG_ERROR( 194562598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 194662598e31SEd Tanous ec); 1947336e96c6SChicago Duan asyncResp->res.result( 1948336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1949336e96c6SChicago Duan return; 1950336e96c6SChicago Duan } 1951336e96c6SChicago Duan 1952336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1953336e96c6SChicago Duan }; 1954336e96c6SChicago Duan 1955336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1956336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1957336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1958336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1959336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 19607e860f15SJohn Edward Broadbent }); 1961400fd1fbSAdriana Kobylak } 1962400fd1fbSAdriana Kobylak 19637e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1964400fd1fbSAdriana Kobylak { 19650fda0f12SGeorge Liu BMCWEB_ROUTE( 19660fda0f12SGeorge Liu app, 196722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1968ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 19697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 197045ca1b86SEd Tanous [&app](const crow::Request& req, 19717e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 197222d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19747e860f15SJohn Edward Broadbent { 197545ca1b86SEd Tanous return; 197645ca1b86SEd Tanous } 197772e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 197899351cd8SEd Tanous req.getHeaderValue("Accept"), 19794a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1980400fd1fbSAdriana Kobylak { 1981002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1982400fd1fbSAdriana Kobylak return; 1983400fd1fbSAdriana Kobylak } 19847f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19857f3e84a1SEd Tanous { 19867f3e84a1SEd Tanous // Option currently returns no systems. TBD 19877f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19887f3e84a1SEd Tanous systemName); 19897f3e84a1SEd Tanous return; 19907f3e84a1SEd Tanous } 199122d268cbSEd Tanous if (systemName != "system") 199222d268cbSEd Tanous { 199322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 199422d268cbSEd Tanous systemName); 199522d268cbSEd Tanous return; 199622d268cbSEd Tanous } 1997400fd1fbSAdriana Kobylak 19987e860f15SJohn Edward Broadbent std::string entryID = param; 1999400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 2000400fd1fbSAdriana Kobylak 2001400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 20025e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 2003400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 2004400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 2005400fd1fbSAdriana Kobylak { 2006002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 2007002d39b4SEd Tanous entryID); 2008400fd1fbSAdriana Kobylak return; 2009400fd1fbSAdriana Kobylak } 2010400fd1fbSAdriana Kobylak if (ec) 2011400fd1fbSAdriana Kobylak { 201262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2013400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2014400fd1fbSAdriana Kobylak return; 2015400fd1fbSAdriana Kobylak } 2016400fd1fbSAdriana Kobylak 2017400fd1fbSAdriana Kobylak int fd = -1; 2018400fd1fbSAdriana Kobylak fd = dup(unixfd); 2019400fd1fbSAdriana Kobylak if (fd == -1) 2020400fd1fbSAdriana Kobylak { 2021400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2022400fd1fbSAdriana Kobylak return; 2023400fd1fbSAdriana Kobylak } 2024400fd1fbSAdriana Kobylak 2025400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 2026400fd1fbSAdriana Kobylak if (size == -1) 2027400fd1fbSAdriana Kobylak { 2028400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2029400fd1fbSAdriana Kobylak return; 2030400fd1fbSAdriana Kobylak } 2031400fd1fbSAdriana Kobylak 2032400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 2033400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 2034400fd1fbSAdriana Kobylak if (size > maxFileSize) 2035400fd1fbSAdriana Kobylak { 203662598e31SEd Tanous BMCWEB_LOG_ERROR("File size exceeds maximum allowed size of {}", 203762598e31SEd Tanous maxFileSize); 2038400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2039400fd1fbSAdriana Kobylak return; 2040400fd1fbSAdriana Kobylak } 2041400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 2042400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 2043400fd1fbSAdriana Kobylak if (rc == -1) 2044400fd1fbSAdriana Kobylak { 2045400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2046400fd1fbSAdriana Kobylak return; 2047400fd1fbSAdriana Kobylak } 2048400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 2049400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 2050400fd1fbSAdriana Kobylak { 2051400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2052400fd1fbSAdriana Kobylak return; 2053400fd1fbSAdriana Kobylak } 2054400fd1fbSAdriana Kobylak close(fd); 2055400fd1fbSAdriana Kobylak 2056400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 2057002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 2058400fd1fbSAdriana Kobylak 2059d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 2060400fd1fbSAdriana Kobylak "application/octet-stream"); 2061d9f6c621SEd Tanous asyncResp->res.addHeader( 2062d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 2063400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 2064400fd1fbSAdriana Kobylak }, 2065400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 2066400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 2067400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 20687e860f15SJohn Edward Broadbent }); 20691da66f75SEd Tanous } 20701da66f75SEd Tanous 2071b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2072b7028ebfSSpencer Ku 2073b7028ebfSSpencer Ku inline bool 2074b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2075b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2076b7028ebfSSpencer Ku { 2077b7028ebfSSpencer Ku std::error_code ec; 2078b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2079b7028ebfSSpencer Ku if (ec) 2080b7028ebfSSpencer Ku { 2081bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2082b7028ebfSSpencer Ku return false; 2083b7028ebfSSpencer Ku } 2084b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2085b7028ebfSSpencer Ku { 2086b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2087b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2088b7028ebfSSpencer Ku // path 208911ba3979SEd Tanous if (filename.starts_with("log")) 2090b7028ebfSSpencer Ku { 2091b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2092b7028ebfSSpencer Ku } 2093b7028ebfSSpencer Ku } 2094b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2095b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2096b7028ebfSSpencer Ku // descending order. 2097b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2098b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2099b7028ebfSSpencer Ku 2100b7028ebfSSpencer Ku return true; 2101b7028ebfSSpencer Ku } 2102b7028ebfSSpencer Ku 210302cad96eSEd Tanous inline bool getHostLoggerEntries( 210402cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 210502cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2106b7028ebfSSpencer Ku { 2107b7028ebfSSpencer Ku GzFileReader logFile; 2108b7028ebfSSpencer Ku 2109b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2110b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2111b7028ebfSSpencer Ku { 2112b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2113b7028ebfSSpencer Ku { 211462598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2115b7028ebfSSpencer Ku return false; 2116b7028ebfSSpencer Ku } 2117b7028ebfSSpencer Ku } 2118b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2119b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2120b7028ebfSSpencer Ku if (!lastMessage.empty()) 2121b7028ebfSSpencer Ku { 2122b7028ebfSSpencer Ku logCount++; 2123b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2124b7028ebfSSpencer Ku { 2125b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2126b7028ebfSSpencer Ku } 2127b7028ebfSSpencer Ku } 2128b7028ebfSSpencer Ku return true; 2129b7028ebfSSpencer Ku } 2130b7028ebfSSpencer Ku 2131b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2132b7028ebfSSpencer Ku const std::string& msg, 21336d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2134b7028ebfSSpencer Ku { 2135b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 21369c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2137ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2138ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2139ef4c65b7SEd Tanous logEntryID); 21406d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 21416d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 21426d6574c9SJason M. Bills logEntryJson["Message"] = msg; 21436d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 21446d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 21456d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2146b7028ebfSSpencer Ku } 2147b7028ebfSSpencer Ku 2148b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2149b7028ebfSSpencer Ku { 215022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2151b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 21521476687dSEd Tanous .methods(boost::beast::http::verb::get)( 21531476687dSEd Tanous [&app](const crow::Request& req, 215422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 215522d268cbSEd Tanous const std::string& systemName) { 21563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 215745ca1b86SEd Tanous { 215845ca1b86SEd Tanous return; 215945ca1b86SEd Tanous } 21607f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 21617f3e84a1SEd Tanous { 21627f3e84a1SEd Tanous // Option currently returns no systems. TBD 21637f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21647f3e84a1SEd Tanous systemName); 21657f3e84a1SEd Tanous return; 21667f3e84a1SEd Tanous } 216722d268cbSEd Tanous if (systemName != "system") 216822d268cbSEd Tanous { 216922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 217022d268cbSEd Tanous systemName); 217122d268cbSEd Tanous return; 217222d268cbSEd Tanous } 2173b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2174b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2175b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2176b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2177b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2178b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2179b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21801476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 21811476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2182b7028ebfSSpencer Ku }); 2183b7028ebfSSpencer Ku } 2184b7028ebfSSpencer Ku 2185b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2186b7028ebfSSpencer Ku { 2187b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 218822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2189b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2190002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2191002d39b4SEd Tanous [&app](const crow::Request& req, 219222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219322d268cbSEd Tanous const std::string& systemName) { 2194c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2195c937d2bfSEd Tanous .canDelegateTop = true, 2196c937d2bfSEd Tanous .canDelegateSkip = true, 2197c937d2bfSEd Tanous }; 2198c937d2bfSEd Tanous query_param::Query delegatedQuery; 2199c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22003ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2201b7028ebfSSpencer Ku { 2202b7028ebfSSpencer Ku return; 2203b7028ebfSSpencer Ku } 22047f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22057f3e84a1SEd Tanous { 22067f3e84a1SEd Tanous // Option currently returns no systems. TBD 22077f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22087f3e84a1SEd Tanous systemName); 22097f3e84a1SEd Tanous return; 22107f3e84a1SEd Tanous } 221122d268cbSEd Tanous if (systemName != "system") 221222d268cbSEd Tanous { 221322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 221422d268cbSEd Tanous systemName); 221522d268cbSEd Tanous return; 221622d268cbSEd Tanous } 2217b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2218b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2219b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2220b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2221b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2222b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2223b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 22240fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2225b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2226b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2227b7028ebfSSpencer Ku 2228b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2229b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2230b7028ebfSSpencer Ku { 2231bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2232b7028ebfSSpencer Ku return; 2233b7028ebfSSpencer Ku } 22343648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 22353648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 22365143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2237b7028ebfSSpencer Ku size_t logCount = 0; 2238b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2239b7028ebfSSpencer Ku // control by skip and top. 2240b7028ebfSSpencer Ku std::vector<std::string> logEntries; 22413648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 22423648c8beSEd Tanous logCount)) 2243b7028ebfSSpencer Ku { 2244b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2245b7028ebfSSpencer Ku return; 2246b7028ebfSSpencer Ku } 2247b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2248b7028ebfSSpencer Ku // log count 224926f6976fSEd Tanous if (logEntries.empty()) 2250b7028ebfSSpencer Ku { 2251b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2252b7028ebfSSpencer Ku return; 2253b7028ebfSSpencer Ku } 225426f6976fSEd Tanous if (!logEntries.empty()) 2255b7028ebfSSpencer Ku { 2256b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2257b7028ebfSSpencer Ku { 22586d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22593648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 22603648c8beSEd Tanous hostLogEntry); 2261b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2262b7028ebfSSpencer Ku } 2263b7028ebfSSpencer Ku 2264b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 22653648c8beSEd Tanous if (skip + top < logCount) 2266b7028ebfSSpencer Ku { 2267b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 22680fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 22693648c8beSEd Tanous std::to_string(skip + top); 2270b7028ebfSSpencer Ku } 2271b7028ebfSSpencer Ku } 2272b7028ebfSSpencer Ku }); 2273b7028ebfSSpencer Ku } 2274b7028ebfSSpencer Ku 2275b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2276b7028ebfSSpencer Ku { 2277b7028ebfSSpencer Ku BMCWEB_ROUTE( 227822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2279b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2280b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 228145ca1b86SEd Tanous [&app](const crow::Request& req, 2282b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 228322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 228545ca1b86SEd Tanous { 228645ca1b86SEd Tanous return; 228745ca1b86SEd Tanous } 22887f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22897f3e84a1SEd Tanous { 22907f3e84a1SEd Tanous // Option currently returns no systems. TBD 22917f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22927f3e84a1SEd Tanous systemName); 22937f3e84a1SEd Tanous return; 22947f3e84a1SEd Tanous } 229522d268cbSEd Tanous if (systemName != "system") 229622d268cbSEd Tanous { 229722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 229822d268cbSEd Tanous systemName); 229922d268cbSEd Tanous return; 230022d268cbSEd Tanous } 2301b7028ebfSSpencer Ku const std::string& targetID = param; 2302b7028ebfSSpencer Ku 2303b7028ebfSSpencer Ku uint64_t idInt = 0; 2304ca45aa3cSEd Tanous 230584396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 230684396af9SPatrick Williams idInt); 23079db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 23089db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2309b7028ebfSSpencer Ku { 23109db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2311b7028ebfSSpencer Ku return; 2312b7028ebfSSpencer Ku } 2313b7028ebfSSpencer Ku 2314b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2315b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2316b7028ebfSSpencer Ku { 2317bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2318b7028ebfSSpencer Ku return; 2319b7028ebfSSpencer Ku } 2320b7028ebfSSpencer Ku 2321b7028ebfSSpencer Ku size_t logCount = 0; 23223648c8beSEd Tanous size_t top = 1; 2323b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2324b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2325b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2326b7028ebfSSpencer Ku // get that entry 2327002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2328002d39b4SEd Tanous logCount)) 2329b7028ebfSSpencer Ku { 2330b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2331b7028ebfSSpencer Ku return; 2332b7028ebfSSpencer Ku } 2333b7028ebfSSpencer Ku 2334b7028ebfSSpencer Ku if (!logEntries.empty()) 2335b7028ebfSSpencer Ku { 23366d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23376d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 23386d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2339b7028ebfSSpencer Ku return; 2340b7028ebfSSpencer Ku } 2341b7028ebfSSpencer Ku 2342b7028ebfSSpencer Ku // Requested ID was not found 23439db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2344b7028ebfSSpencer Ku }); 2345b7028ebfSSpencer Ku } 2346b7028ebfSSpencer Ku 2347dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2348fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2349fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 23501da66f75SEd Tanous { 23513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 235245ca1b86SEd Tanous { 235345ca1b86SEd Tanous return; 235445ca1b86SEd Tanous } 23557e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 23567e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2357e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 23581da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2359e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2360e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2361002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2362e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 23631da66f75SEd Tanous "Collection of LogServices for this Manager"; 2364002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2365c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2366fdd26906SClaire Weinan 2367c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2368613dabeaSEd Tanous nlohmann::json::object_t journal; 2369613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2370b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2371c4bf6374SJason M. Bills #endif 2372fdd26906SClaire Weinan 2373fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2374fdd26906SClaire Weinan 2375fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 237615912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 23777a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 23787a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 23797a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2380fdd26906SClaire Weinan [asyncResp]( 23817a1dbc48SGeorge Liu const boost::system::error_code& ec, 2382fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2383fdd26906SClaire Weinan if (ec) 2384fdd26906SClaire Weinan { 238562598e31SEd Tanous BMCWEB_LOG_ERROR( 238662598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 238762598e31SEd Tanous ec); 2388fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2389fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2390fdd26906SClaire Weinan return; 2391fdd26906SClaire Weinan } 2392fdd26906SClaire Weinan 2393fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2394fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2395fdd26906SClaire Weinan 2396fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2397fdd26906SClaire Weinan { 2398fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2399fdd26906SClaire Weinan { 2400613dabeaSEd Tanous nlohmann::json::object_t member; 2401613dabeaSEd Tanous member["@odata.id"] = 2402613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2403b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2404fdd26906SClaire Weinan } 2405fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2406fdd26906SClaire Weinan { 2407613dabeaSEd Tanous nlohmann::json::object_t member; 2408613dabeaSEd Tanous member["@odata.id"] = 2409613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2410b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2411fdd26906SClaire Weinan } 2412fdd26906SClaire Weinan } 2413fdd26906SClaire Weinan 2414e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2415fdd26906SClaire Weinan logServiceArrayLocal.size(); 24167a1dbc48SGeorge Liu }); 2417fdd26906SClaire Weinan #endif 2418fdd26906SClaire Weinan } 2419fdd26906SClaire Weinan 2420fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2421fdd26906SClaire Weinan { 2422fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2423fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2424fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2425dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2426e1f26343SJason M. Bills } 2427e1f26343SJason M. Bills 24287e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2429e1f26343SJason M. Bills { 24307e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2431ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 24327e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 243345ca1b86SEd Tanous [&app](const crow::Request& req, 243445ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 24353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 24367e860f15SJohn Edward Broadbent { 243745ca1b86SEd Tanous return; 243845ca1b86SEd Tanous } 2439e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2440e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 24410f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24420f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2443002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2444002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2445ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2446e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 24477c8c4058STejas Patil 24487c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 24492b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2450002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 24517c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 24527c8c4058STejas Patil redfishDateTimeOffset.second; 24537c8c4058STejas Patil 24541476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 24551476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 24567e860f15SJohn Edward Broadbent }); 2457e1f26343SJason M. Bills } 2458e1f26343SJason M. Bills 24593a48b3a2SJason M. Bills static int 24603a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2461e1f26343SJason M. Bills sd_journal* journal, 24623a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2463e1f26343SJason M. Bills { 2464e1f26343SJason M. Bills // Get the Log Entry contents 2465e1f26343SJason M. Bills int ret = 0; 2466e1f26343SJason M. Bills 2467a8fe54f0SJason M. Bills std::string message; 2468a8fe54f0SJason M. Bills std::string_view syslogID; 2469a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2470a8fe54f0SJason M. Bills if (ret < 0) 2471a8fe54f0SJason M. Bills { 2472bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 247362598e31SEd Tanous strerror(-ret)); 2474a8fe54f0SJason M. Bills } 2475a8fe54f0SJason M. Bills if (!syslogID.empty()) 2476a8fe54f0SJason M. Bills { 2477a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2478a8fe54f0SJason M. Bills } 2479a8fe54f0SJason M. Bills 248039e77504SEd Tanous std::string_view msg; 248116428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2482e1f26343SJason M. Bills if (ret < 0) 2483e1f26343SJason M. Bills { 248462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2485e1f26343SJason M. Bills return 1; 2486e1f26343SJason M. Bills } 2487a8fe54f0SJason M. Bills message += std::string(msg); 2488e1f26343SJason M. Bills 2489e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2490271584abSEd Tanous long int severity = 8; // Default to an invalid priority 249116428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2492e1f26343SJason M. Bills if (ret < 0) 2493e1f26343SJason M. Bills { 2494bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2495e1f26343SJason M. Bills } 2496e1f26343SJason M. Bills 2497e1f26343SJason M. Bills // Get the Created time from the timestamp 249816428a1aSJason M. Bills std::string entryTimeStr; 249916428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2500e1f26343SJason M. Bills { 250116428a1aSJason M. Bills return 1; 2502e1f26343SJason M. Bills } 2503e1f26343SJason M. Bills 2504e1f26343SJason M. Bills // Fill in the log entry with the gathered data 25059c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2506ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2507ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2508eddfc437SWilly Tu bmcJournalLogEntryID); 250984afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 251084afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 251184afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 251284afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 251384afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2514738c1e61SPatrick Williams : severity <= 4 ? "Warning" 251584afc48bSJason M. Bills : "OK"; 251684afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 251784afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2518e1f26343SJason M. Bills return 0; 2519e1f26343SJason M. Bills } 2520e1f26343SJason M. Bills 25217e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2522e1f26343SJason M. Bills { 25237e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2524ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2525002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2526002d39b4SEd Tanous [&app](const crow::Request& req, 2527002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2528c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2529c937d2bfSEd Tanous .canDelegateTop = true, 2530c937d2bfSEd Tanous .canDelegateSkip = true, 2531c937d2bfSEd Tanous }; 2532c937d2bfSEd Tanous query_param::Query delegatedQuery; 2533c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 25343ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2535193ad2faSJason M. Bills { 2536193ad2faSJason M. Bills return; 2537193ad2faSJason M. Bills } 25383648c8beSEd Tanous 25393648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 25405143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 25413648c8beSEd Tanous 25427e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 25437e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2544e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2545e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 25460f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 25470f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2548e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2549e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2550e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 25510fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2552e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2553e1f26343SJason M. Bills 25547e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 25557e860f15SJohn Edward Broadbent // unique ID for each entry 2556e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2557e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2558e1f26343SJason M. Bills if (ret < 0) 2559e1f26343SJason M. Bills { 256062598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2561f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2562e1f26343SJason M. Bills return; 2563e1f26343SJason M. Bills } 25640fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 25650fda0f12SGeorge Liu journalTmp, sd_journal_close); 2566e1f26343SJason M. Bills journalTmp = nullptr; 2567b01bf299SEd Tanous uint64_t entryCount = 0; 2568e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2569e85d6b16SJason M. Bills bool firstEntry = true; 2570e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2571e1f26343SJason M. Bills { 2572193ad2faSJason M. Bills entryCount++; 25737e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 25747e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 25753648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2576193ad2faSJason M. Bills { 2577193ad2faSJason M. Bills continue; 2578193ad2faSJason M. Bills } 2579193ad2faSJason M. Bills 258016428a1aSJason M. Bills std::string idStr; 2581e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2582e1f26343SJason M. Bills { 2583e1f26343SJason M. Bills continue; 2584e1f26343SJason M. Bills } 2585e85d6b16SJason M. Bills firstEntry = false; 2586e85d6b16SJason M. Bills 25873a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2588c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2589c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2590e1f26343SJason M. Bills { 2591f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2592e1f26343SJason M. Bills return; 2593e1f26343SJason M. Bills } 2594b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2595e1f26343SJason M. Bills } 2596193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 25973648c8beSEd Tanous if (skip + top < entryCount) 2598193ad2faSJason M. Bills { 2599193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 26000fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 26013648c8beSEd Tanous std::to_string(skip + top); 2602193ad2faSJason M. Bills } 26037e860f15SJohn Edward Broadbent }); 2604e1f26343SJason M. Bills } 2605e1f26343SJason M. Bills 26067e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2607e1f26343SJason M. Bills { 26087e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26097e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2610ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 26117e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 261245ca1b86SEd Tanous [&app](const crow::Request& req, 26137e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26147e860f15SJohn Edward Broadbent const std::string& entryID) { 26153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 261645ca1b86SEd Tanous { 261745ca1b86SEd Tanous return; 261845ca1b86SEd Tanous } 2619e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2620e1f26343SJason M. Bills uint64_t ts = 0; 2621271584abSEd Tanous uint64_t index = 0; 26228d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2623e1f26343SJason M. Bills { 262416428a1aSJason M. Bills return; 2625e1f26343SJason M. Bills } 2626e1f26343SJason M. Bills 2627e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2628e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2629e1f26343SJason M. Bills if (ret < 0) 2630e1f26343SJason M. Bills { 263162598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2632f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2633e1f26343SJason M. Bills return; 2634e1f26343SJason M. Bills } 2635002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2636002d39b4SEd Tanous journalTmp, sd_journal_close); 2637e1f26343SJason M. Bills journalTmp = nullptr; 26387e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 26397e860f15SJohn Edward Broadbent // index tracking the unique ID 2640af07e3f5SJason M. Bills std::string idStr; 2641af07e3f5SJason M. Bills bool firstEntry = true; 2642e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 26432056b6d1SManojkiran Eda if (ret < 0) 26442056b6d1SManojkiran Eda { 264562598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 264662598e31SEd Tanous strerror(-ret)); 26472056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 26482056b6d1SManojkiran Eda return; 26492056b6d1SManojkiran Eda } 2650271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2651e1f26343SJason M. Bills { 2652e1f26343SJason M. Bills sd_journal_next(journal.get()); 2653af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2654af07e3f5SJason M. Bills { 2655af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2656af07e3f5SJason M. Bills return; 2657af07e3f5SJason M. Bills } 2658af07e3f5SJason M. Bills firstEntry = false; 2659af07e3f5SJason M. Bills } 2660c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2661af07e3f5SJason M. Bills if (idStr != entryID) 2662c4bf6374SJason M. Bills { 26639db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2664c4bf6374SJason M. Bills return; 2665c4bf6374SJason M. Bills } 2666c4bf6374SJason M. Bills 26673a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2668c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 26693a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2670e1f26343SJason M. Bills { 2671f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2672e1f26343SJason M. Bills return; 2673e1f26343SJason M. Bills } 2674d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 26757e860f15SJohn Edward Broadbent }); 2676c9bb6861Sraviteja-b } 2677c9bb6861Sraviteja-b 2678fdd26906SClaire Weinan inline void 2679fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2680fdd26906SClaire Weinan const std::string& dumpType) 2681c9bb6861Sraviteja-b { 2682fdd26906SClaire Weinan std::string dumpPath; 2683fdd26906SClaire Weinan std::string overWritePolicy; 2684fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2685fdd26906SClaire Weinan 2686fdd26906SClaire Weinan if (dumpType == "BMC") 268745ca1b86SEd Tanous { 2688fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2689fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2690fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2691fdd26906SClaire Weinan } 2692fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2693fdd26906SClaire Weinan { 2694fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2695fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2696fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2697fdd26906SClaire Weinan } 2698fdd26906SClaire Weinan else if (dumpType == "System") 2699fdd26906SClaire Weinan { 2700fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2701fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2702fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2703fdd26906SClaire Weinan } 2704fdd26906SClaire Weinan else 2705fdd26906SClaire Weinan { 270662598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 270762598e31SEd Tanous dumpType); 2708fdd26906SClaire Weinan messages::internalError(asyncResp->res); 270945ca1b86SEd Tanous return; 271045ca1b86SEd Tanous } 2711fdd26906SClaire Weinan 2712fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2713fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2714c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2715fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2716fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2717fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 27187c8c4058STejas Patil 27197c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 27202b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 27210fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 27227c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 27237c8c4058STejas Patil redfishDateTimeOffset.second; 27247c8c4058STejas Patil 2725fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2726fdd26906SClaire Weinan 2727fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2728fdd26906SClaire Weinan { 2729002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 27301476687dSEd Tanous ["target"] = 2731fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2732fdd26906SClaire Weinan } 27330d946211SClaire Weinan 27340d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 27350d946211SClaire Weinan dbus::utility::getSubTreePaths( 27360d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 27370d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 27380d946211SClaire Weinan const boost::system::error_code& ec, 27390d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 27400d946211SClaire Weinan if (ec) 27410d946211SClaire Weinan { 274262598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 27430d946211SClaire Weinan // Assume that getting an error simply means there are no dump 27440d946211SClaire Weinan // LogServices. Return without adding any error response. 27450d946211SClaire Weinan return; 27460d946211SClaire Weinan } 27470d946211SClaire Weinan 27480d946211SClaire Weinan const std::string dbusDumpPath = 27490d946211SClaire Weinan "/xyz/openbmc_project/dump/" + 27500d946211SClaire Weinan boost::algorithm::to_lower_copy(dumpType); 27510d946211SClaire Weinan 27520d946211SClaire Weinan for (const std::string& path : subTreePaths) 27530d946211SClaire Weinan { 27540d946211SClaire Weinan if (path == dbusDumpPath) 27550d946211SClaire Weinan { 27560d946211SClaire Weinan asyncResp->res 27570d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 27580d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 27590d946211SClaire Weinan break; 27600d946211SClaire Weinan } 27610d946211SClaire Weinan } 27620d946211SClaire Weinan }); 2763c9bb6861Sraviteja-b } 2764c9bb6861Sraviteja-b 2765fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2766fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2767fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 27687e860f15SJohn Edward Broadbent { 27693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 277045ca1b86SEd Tanous { 277145ca1b86SEd Tanous return; 277245ca1b86SEd Tanous } 2773fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2774fdd26906SClaire Weinan } 2775c9bb6861Sraviteja-b 277622d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 277722d268cbSEd Tanous crow::App& app, const crow::Request& req, 277822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 277922d268cbSEd Tanous const std::string& chassisId) 278022d268cbSEd Tanous { 278122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 278222d268cbSEd Tanous { 278322d268cbSEd Tanous return; 278422d268cbSEd Tanous } 278522d268cbSEd Tanous if (chassisId != "system") 278622d268cbSEd Tanous { 278722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 278822d268cbSEd Tanous return; 278922d268cbSEd Tanous } 279022d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 279122d268cbSEd Tanous } 279222d268cbSEd Tanous 2793fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2794fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2795fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2796fdd26906SClaire Weinan { 2797fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2798fdd26906SClaire Weinan { 2799fdd26906SClaire Weinan return; 2800fdd26906SClaire Weinan } 2801fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2802fdd26906SClaire Weinan } 2803fdd26906SClaire Weinan 280422d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 280522d268cbSEd Tanous crow::App& app, const crow::Request& req, 280622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 280722d268cbSEd Tanous const std::string& chassisId) 280822d268cbSEd Tanous { 280922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 281022d268cbSEd Tanous { 281122d268cbSEd Tanous return; 281222d268cbSEd Tanous } 281322d268cbSEd Tanous if (chassisId != "system") 281422d268cbSEd Tanous { 281522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 281622d268cbSEd Tanous return; 281722d268cbSEd Tanous } 281822d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 281922d268cbSEd Tanous } 282022d268cbSEd Tanous 2821fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2822fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2823fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2824fdd26906SClaire Weinan const std::string& dumpId) 2825fdd26906SClaire Weinan { 2826fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2827fdd26906SClaire Weinan { 2828fdd26906SClaire Weinan return; 2829fdd26906SClaire Weinan } 2830fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2831fdd26906SClaire Weinan } 283222d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 283322d268cbSEd Tanous crow::App& app, const crow::Request& req, 283422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 283522d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 283622d268cbSEd Tanous { 283722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 283822d268cbSEd Tanous { 283922d268cbSEd Tanous return; 284022d268cbSEd Tanous } 284122d268cbSEd Tanous if (chassisId != "system") 284222d268cbSEd Tanous { 284322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 284422d268cbSEd Tanous return; 284522d268cbSEd Tanous } 284622d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 284722d268cbSEd Tanous } 2848fdd26906SClaire Weinan 2849fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2850fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2851fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2852fdd26906SClaire Weinan const std::string& dumpId) 2853fdd26906SClaire Weinan { 2854fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2855fdd26906SClaire Weinan { 2856fdd26906SClaire Weinan return; 2857fdd26906SClaire Weinan } 2858fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2859fdd26906SClaire Weinan } 2860fdd26906SClaire Weinan 286122d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 286222d268cbSEd Tanous crow::App& app, const crow::Request& req, 286322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286422d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 286522d268cbSEd Tanous { 286622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 286722d268cbSEd Tanous { 286822d268cbSEd Tanous return; 286922d268cbSEd Tanous } 287022d268cbSEd Tanous if (chassisId != "system") 287122d268cbSEd Tanous { 287222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 287322d268cbSEd Tanous return; 287422d268cbSEd Tanous } 287522d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 287622d268cbSEd Tanous } 287722d268cbSEd Tanous 2878fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2879fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2880fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2881fdd26906SClaire Weinan { 2882fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2883fdd26906SClaire Weinan { 2884fdd26906SClaire Weinan return; 2885fdd26906SClaire Weinan } 2886fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2887fdd26906SClaire Weinan } 2888fdd26906SClaire Weinan 288922d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 289022d268cbSEd Tanous crow::App& app, const crow::Request& req, 289122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 28927f3e84a1SEd Tanous const std::string& systemName) 289322d268cbSEd Tanous { 289422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 289522d268cbSEd Tanous { 289622d268cbSEd Tanous return; 289722d268cbSEd Tanous } 28987f3e84a1SEd Tanous 28997f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 290022d268cbSEd Tanous { 29017f3e84a1SEd Tanous // Option currently returns no systems. TBD 29027f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29037f3e84a1SEd Tanous systemName); 29047f3e84a1SEd Tanous return; 29057f3e84a1SEd Tanous } 29067f3e84a1SEd Tanous if (systemName != "system") 29077f3e84a1SEd Tanous { 29087f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29097f3e84a1SEd Tanous systemName); 291022d268cbSEd Tanous return; 291122d268cbSEd Tanous } 291222d268cbSEd Tanous createDump(asyncResp, req, "System"); 291322d268cbSEd Tanous } 291422d268cbSEd Tanous 2915fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2916fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2917fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2918fdd26906SClaire Weinan { 2919fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2920fdd26906SClaire Weinan { 2921fdd26906SClaire Weinan return; 2922fdd26906SClaire Weinan } 2923fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2924fdd26906SClaire Weinan } 2925fdd26906SClaire Weinan 292622d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 292722d268cbSEd Tanous crow::App& app, const crow::Request& req, 292822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29297f3e84a1SEd Tanous const std::string& systemName) 293022d268cbSEd Tanous { 293122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 293222d268cbSEd Tanous { 293322d268cbSEd Tanous return; 293422d268cbSEd Tanous } 29357f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 293622d268cbSEd Tanous { 29377f3e84a1SEd Tanous // Option currently returns no systems. TBD 29387f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29397f3e84a1SEd Tanous systemName); 29407f3e84a1SEd Tanous return; 29417f3e84a1SEd Tanous } 29427f3e84a1SEd Tanous if (systemName != "system") 29437f3e84a1SEd Tanous { 29447f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 29457f3e84a1SEd Tanous systemName); 294622d268cbSEd Tanous return; 294722d268cbSEd Tanous } 294822d268cbSEd Tanous clearDump(asyncResp, "System"); 294922d268cbSEd Tanous } 295022d268cbSEd Tanous 2951fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2952fdd26906SClaire Weinan { 2953fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2954fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2955fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2956fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2957fdd26906SClaire Weinan } 2958fdd26906SClaire Weinan 2959fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2960fdd26906SClaire Weinan { 2961fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2962fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2963fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2964fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2965c9bb6861Sraviteja-b } 2966c9bb6861Sraviteja-b 29677e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2968c9bb6861Sraviteja-b { 29697e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 29707e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2971ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2972fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2973fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2974fdd26906SClaire Weinan 29757e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 29767e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2977ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2978fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2979fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2980c9bb6861Sraviteja-b } 2981c9bb6861Sraviteja-b 29827e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2983c9bb6861Sraviteja-b { 29840fda0f12SGeorge Liu BMCWEB_ROUTE( 29850fda0f12SGeorge Liu app, 29860fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2987ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29887e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2989fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2990fdd26906SClaire Weinan std::ref(app), "BMC")); 2991a43be80fSAsmitha Karunanithi } 2992a43be80fSAsmitha Karunanithi 29937e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 299480319af1SAsmitha Karunanithi { 29950fda0f12SGeorge Liu BMCWEB_ROUTE( 29960fda0f12SGeorge Liu app, 29970fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2998ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2999fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3000fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 300145ca1b86SEd Tanous } 3002fdd26906SClaire Weinan 3003fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3004fdd26906SClaire Weinan { 3005fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 3006fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3007fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3008fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3009fdd26906SClaire Weinan } 3010fdd26906SClaire Weinan 3011fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3012fdd26906SClaire Weinan { 3013fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 3014fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3015fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3016fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3017fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3018fdd26906SClaire Weinan } 3019fdd26906SClaire Weinan 3020fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3021fdd26906SClaire Weinan { 3022fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3023fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3024fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3025fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3026fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3027fdd26906SClaire Weinan 3028fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3029fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3030fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3031fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3032fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3033fdd26906SClaire Weinan } 3034fdd26906SClaire Weinan 3035fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3036fdd26906SClaire Weinan { 3037fdd26906SClaire Weinan BMCWEB_ROUTE( 3038fdd26906SClaire Weinan app, 3039fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 3040fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3041fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3042fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 30435cb1dd27SAsmitha Karunanithi } 30445cb1dd27SAsmitha Karunanithi 30457e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 30465cb1dd27SAsmitha Karunanithi { 304722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3048ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 30496ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 305022d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 30515cb1dd27SAsmitha Karunanithi } 30525cb1dd27SAsmitha Karunanithi 30537e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 30547e860f15SJohn Edward Broadbent { 305522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3056ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 305722d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 305822d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 305922d268cbSEd Tanous std::ref(app))); 30605cb1dd27SAsmitha Karunanithi } 30615cb1dd27SAsmitha Karunanithi 30627e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 30635cb1dd27SAsmitha Karunanithi { 30647e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 306522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3066ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 30676ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 306822d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 30698d1b46d7Szhanghch05 30707e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 307122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3072ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 30736ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 307422d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 30755cb1dd27SAsmitha Karunanithi } 3076c9bb6861Sraviteja-b 30777e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3078c9bb6861Sraviteja-b { 30790fda0f12SGeorge Liu BMCWEB_ROUTE( 30800fda0f12SGeorge Liu app, 308122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3082ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 308322d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 308422d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 308522d268cbSEd Tanous std::ref(app))); 3086a43be80fSAsmitha Karunanithi } 3087a43be80fSAsmitha Karunanithi 30887e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3089a43be80fSAsmitha Karunanithi { 30900fda0f12SGeorge Liu BMCWEB_ROUTE( 30910fda0f12SGeorge Liu app, 309222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3093ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 30946ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 309522d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3096013487e5Sraviteja-b } 3097013487e5Sraviteja-b 30987e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 30991da66f75SEd Tanous { 31003946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31013946028dSAppaRao Puli // method for security reasons. 31021da66f75SEd Tanous /** 31031da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31041da66f75SEd Tanous */ 310522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3106ed398213SEd Tanous // This is incorrect, should be: 3107ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3108432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3109002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3110002d39b4SEd Tanous [&app](const crow::Request& req, 311122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 311222d268cbSEd Tanous const std::string& systemName) { 31133ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 311445ca1b86SEd Tanous { 311545ca1b86SEd Tanous return; 311645ca1b86SEd Tanous } 31177f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 31187f3e84a1SEd Tanous { 31197f3e84a1SEd Tanous // Option currently returns no systems. TBD 31207f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31217f3e84a1SEd Tanous systemName); 31227f3e84a1SEd Tanous return; 31237f3e84a1SEd Tanous } 312422d268cbSEd Tanous if (systemName != "system") 312522d268cbSEd Tanous { 312622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 312722d268cbSEd Tanous systemName); 312822d268cbSEd Tanous return; 312922d268cbSEd Tanous } 313022d268cbSEd Tanous 31317e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 31327e860f15SJohn Edward Broadbent // SubRoute 31330f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3134424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3135e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31368e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 31374f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 31384f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 313915b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3140e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3141e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 31427c8c4058STejas Patil 31437c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 31442b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 31457c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 31467c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 31477c8c4058STejas Patil redfishDateTimeOffset.second; 31487c8c4058STejas Patil 31491476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3150ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3151002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 31521476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3153002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 31541476687dSEd Tanous ["target"] = 31551476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 31567e860f15SJohn Edward Broadbent }); 31571da66f75SEd Tanous } 31581da66f75SEd Tanous 31597e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 31605b61b5e8SJason M. Bills { 31610fda0f12SGeorge Liu BMCWEB_ROUTE( 31620fda0f12SGeorge Liu app, 316322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3164ed398213SEd Tanous // This is incorrect, should be: 3165ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3166432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 31677e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 316845ca1b86SEd Tanous [&app](const crow::Request& req, 316922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 317022d268cbSEd Tanous const std::string& systemName) { 31713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 317245ca1b86SEd Tanous { 317345ca1b86SEd Tanous return; 317445ca1b86SEd Tanous } 31757f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 31767f3e84a1SEd Tanous { 31777f3e84a1SEd Tanous // Option currently returns no systems. TBD 31787f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 31797f3e84a1SEd Tanous systemName); 31807f3e84a1SEd Tanous return; 31817f3e84a1SEd Tanous } 318222d268cbSEd Tanous if (systemName != "system") 318322d268cbSEd Tanous { 318422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 318522d268cbSEd Tanous systemName); 318622d268cbSEd Tanous return; 318722d268cbSEd Tanous } 31885b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 31895e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3190cb13a392SEd Tanous const std::string&) { 31915b61b5e8SJason M. Bills if (ec) 31925b61b5e8SJason M. Bills { 31935b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 31945b61b5e8SJason M. Bills return; 31955b61b5e8SJason M. Bills } 31965b61b5e8SJason M. Bills messages::success(asyncResp->res); 31975b61b5e8SJason M. Bills }, 3198002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 31997e860f15SJohn Edward Broadbent }); 32005b61b5e8SJason M. Bills } 32015b61b5e8SJason M. Bills 32028d1b46d7Szhanghch05 static void 32038d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 32048d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3205e855dd28SJason M. Bills { 3206043a0536SJohnathan Mantey auto getStoredLogCallback = 3207b9d36b47SEd Tanous [asyncResp, logID, 32085e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3209b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3210e855dd28SJason M. Bills if (ec) 3211e855dd28SJason M. Bills { 321262598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 32131ddcf01aSJason M. Bills if (ec.value() == 32141ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 32151ddcf01aSJason M. Bills { 3216002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32171ddcf01aSJason M. Bills } 32181ddcf01aSJason M. Bills else 32191ddcf01aSJason M. Bills { 3220e855dd28SJason M. Bills messages::internalError(asyncResp->res); 32211ddcf01aSJason M. Bills } 3222e855dd28SJason M. Bills return; 3223e855dd28SJason M. Bills } 3224043a0536SJohnathan Mantey 3225043a0536SJohnathan Mantey std::string timestamp{}; 3226043a0536SJohnathan Mantey std::string filename{}; 3227043a0536SJohnathan Mantey std::string logfile{}; 32282c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3229043a0536SJohnathan Mantey 3230043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3231e855dd28SJason M. Bills { 32329db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3233e855dd28SJason M. Bills return; 3234e855dd28SJason M. Bills } 3235e855dd28SJason M. Bills 3236043a0536SJohnathan Mantey std::string crashdumpURI = 3237e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3238043a0536SJohnathan Mantey logID + "/" + filename; 323984afc48bSJason M. Bills nlohmann::json::object_t logEntry; 32409c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3241ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3242ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3243ef4c65b7SEd Tanous logID); 324484afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 324584afc48bSJason M. Bills logEntry["Id"] = logID; 324684afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 324784afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 324884afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 324984afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 325084afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 32512b20ef6eSJason M. Bills 32522b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 32532b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 32542b20ef6eSJason M. Bills // directly 32552b20ef6eSJason M. Bills if (logEntryJson.is_array()) 32562b20ef6eSJason M. Bills { 32572b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 32582b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 32592b20ef6eSJason M. Bills logEntryJson.size(); 32602b20ef6eSJason M. Bills } 32612b20ef6eSJason M. Bills else 32622b20ef6eSJason M. Bills { 3263d405bb51SJason M. Bills logEntryJson.update(logEntry); 32642b20ef6eSJason M. Bills } 3265e855dd28SJason M. Bills }; 3266d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3267d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3268d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3269d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3270e855dd28SJason M. Bills } 3271e855dd28SJason M. Bills 32727e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 32731da66f75SEd Tanous { 32743946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32753946028dSAppaRao Puli // method for security reasons. 32761da66f75SEd Tanous /** 32771da66f75SEd Tanous * Functions triggers appropriate requests on DBus 32781da66f75SEd Tanous */ 32797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 328022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3281ed398213SEd Tanous // This is incorrect, should be. 3282ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3283432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3284002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3285002d39b4SEd Tanous [&app](const crow::Request& req, 328622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 328722d268cbSEd Tanous const std::string& systemName) { 32883ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 328945ca1b86SEd Tanous { 329045ca1b86SEd Tanous return; 329145ca1b86SEd Tanous } 32927f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32937f3e84a1SEd Tanous { 32947f3e84a1SEd Tanous // Option currently returns no systems. TBD 32957f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32967f3e84a1SEd Tanous systemName); 32977f3e84a1SEd Tanous return; 32987f3e84a1SEd Tanous } 329922d268cbSEd Tanous if (systemName != "system") 330022d268cbSEd Tanous { 330122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 330222d268cbSEd Tanous systemName); 330322d268cbSEd Tanous return; 330422d268cbSEd Tanous } 330522d268cbSEd Tanous 33067a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 33077a1dbc48SGeorge Liu crashdumpInterface}; 33087a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 33097a1dbc48SGeorge Liu "/", 0, interfaces, 33107a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 33112b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 33121da66f75SEd Tanous if (ec) 33131da66f75SEd Tanous { 33141da66f75SEd Tanous if (ec.value() != 33151da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 33161da66f75SEd Tanous { 331762598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 331862598e31SEd Tanous ec.message()); 3319f12894f8SJason M. Bills messages::internalError(asyncResp->res); 33201da66f75SEd Tanous return; 33211da66f75SEd Tanous } 33221da66f75SEd Tanous } 3323e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 33241da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 33250f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3326424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3327002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3328e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3329424c4176SJason M. Bills "Collection of Crashdump Entries"; 3330002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3331a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 33322b20ef6eSJason M. Bills 33332b20ef6eSJason M. Bills for (const std::string& path : resp) 33341da66f75SEd Tanous { 33352b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3336e855dd28SJason M. Bills // Get the log ID 33372b20ef6eSJason M. Bills std::string logID = objPath.filename(); 33382b20ef6eSJason M. Bills if (logID.empty()) 33391da66f75SEd Tanous { 3340e855dd28SJason M. Bills continue; 33411da66f75SEd Tanous } 3342e855dd28SJason M. Bills // Add the log entry to the array 33432b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 33442b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 33451da66f75SEd Tanous } 33467a1dbc48SGeorge Liu }); 33477e860f15SJohn Edward Broadbent }); 33481da66f75SEd Tanous } 33491da66f75SEd Tanous 33507e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 33511da66f75SEd Tanous { 33523946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33533946028dSAppaRao Puli // method for security reasons. 33541da66f75SEd Tanous 33557e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 335622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3357ed398213SEd Tanous // this is incorrect, should be 3358ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3359432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 33607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 336145ca1b86SEd Tanous [&app](const crow::Request& req, 33627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 336322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 33643ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 336545ca1b86SEd Tanous { 336645ca1b86SEd Tanous return; 336745ca1b86SEd Tanous } 33687f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 33697f3e84a1SEd Tanous { 33707f3e84a1SEd Tanous // Option currently returns no systems. TBD 33717f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33727f3e84a1SEd Tanous systemName); 33737f3e84a1SEd Tanous return; 33747f3e84a1SEd Tanous } 337522d268cbSEd Tanous if (systemName != "system") 337622d268cbSEd Tanous { 337722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 337822d268cbSEd Tanous systemName); 337922d268cbSEd Tanous return; 338022d268cbSEd Tanous } 33817e860f15SJohn Edward Broadbent const std::string& logID = param; 3382e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 33837e860f15SJohn Edward Broadbent }); 3384e855dd28SJason M. Bills } 3385e855dd28SJason M. Bills 33867e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3387e855dd28SJason M. Bills { 33883946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33893946028dSAppaRao Puli // method for security reasons. 33907e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 33917e860f15SJohn Edward Broadbent app, 339222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3393ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 33947e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3395a4ce114aSNan Zhou [](const crow::Request& req, 33967e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 339722d268cbSEd Tanous const std::string& systemName, const std::string& logID, 339822d268cbSEd Tanous const std::string& fileName) { 33992a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 34002a9beeedSShounak Mitra // Redfish resource. 340122d268cbSEd Tanous 34027f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34037f3e84a1SEd Tanous { 34047f3e84a1SEd Tanous // Option currently returns no systems. TBD 34057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34067f3e84a1SEd Tanous systemName); 34077f3e84a1SEd Tanous return; 34087f3e84a1SEd Tanous } 340922d268cbSEd Tanous if (systemName != "system") 341022d268cbSEd Tanous { 341122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 341222d268cbSEd Tanous systemName); 341322d268cbSEd Tanous return; 341422d268cbSEd Tanous } 341522d268cbSEd Tanous 3416043a0536SJohnathan Mantey auto getStoredLogCallback = 341739662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 34185e7e2dc5SEd Tanous const boost::system::error_code& ec, 3419002d39b4SEd Tanous const std::vector< 3420002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 34217e860f15SJohn Edward Broadbent resp) { 34221da66f75SEd Tanous if (ec) 34231da66f75SEd Tanous { 342462598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3425f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34261da66f75SEd Tanous return; 34271da66f75SEd Tanous } 3428e855dd28SJason M. Bills 3429043a0536SJohnathan Mantey std::string dbusFilename{}; 3430043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3431043a0536SJohnathan Mantey std::string dbusFilepath{}; 3432043a0536SJohnathan Mantey 3433002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3434002d39b4SEd Tanous dbusFilepath); 3435043a0536SJohnathan Mantey 3436043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3437043a0536SJohnathan Mantey dbusFilepath.empty()) 34381da66f75SEd Tanous { 34399db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 34401da66f75SEd Tanous return; 34411da66f75SEd Tanous } 3442e855dd28SJason M. Bills 3443043a0536SJohnathan Mantey // Verify the file name parameter is correct 3444043a0536SJohnathan Mantey if (fileName != dbusFilename) 3445043a0536SJohnathan Mantey { 34469db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3447043a0536SJohnathan Mantey return; 3448043a0536SJohnathan Mantey } 3449043a0536SJohnathan Mantey 3450043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3451043a0536SJohnathan Mantey { 34529db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3453043a0536SJohnathan Mantey return; 3454043a0536SJohnathan Mantey } 3455002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3456002d39b4SEd Tanous asyncResp->res.body() = 3457002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3458043a0536SJohnathan Mantey 34597e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 34607e860f15SJohn Edward Broadbent // from a browser 3461d9f6c621SEd Tanous asyncResp->res.addHeader( 3462d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 34631da66f75SEd Tanous }; 3464d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3465d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3466d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3467d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 34687e860f15SJohn Edward Broadbent }); 34691da66f75SEd Tanous } 34701da66f75SEd Tanous 3471c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3472c5a4c82aSJason M. Bills { 3473c5a4c82aSJason M. Bills onDemand, 3474c5a4c82aSJason M. Bills telemetry, 3475c5a4c82aSJason M. Bills invalid, 3476c5a4c82aSJason M. Bills }; 3477c5a4c82aSJason M. Bills 347826ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3479c5a4c82aSJason M. Bills { 3480c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3481c5a4c82aSJason M. Bills { 3482c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3483c5a4c82aSJason M. Bills } 3484c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3485c5a4c82aSJason M. Bills { 3486c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3487c5a4c82aSJason M. Bills } 3488c5a4c82aSJason M. Bills 3489c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3490c5a4c82aSJason M. Bills } 3491c5a4c82aSJason M. Bills 34927e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 34931da66f75SEd Tanous { 34943946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34953946028dSAppaRao Puli // method for security reasons. 34960fda0f12SGeorge Liu BMCWEB_ROUTE( 34970fda0f12SGeorge Liu app, 349822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3499ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3500ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3501432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3502002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3503002d39b4SEd Tanous [&app](const crow::Request& req, 350422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350522d268cbSEd Tanous const std::string& systemName) { 35063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 350745ca1b86SEd Tanous { 350845ca1b86SEd Tanous return; 350945ca1b86SEd Tanous } 351022d268cbSEd Tanous 35117f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35127f3e84a1SEd Tanous { 35137f3e84a1SEd Tanous // Option currently returns no systems. TBD 35147f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35157f3e84a1SEd Tanous systemName); 35167f3e84a1SEd Tanous return; 35177f3e84a1SEd Tanous } 351822d268cbSEd Tanous if (systemName != "system") 351922d268cbSEd Tanous { 352022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 352122d268cbSEd Tanous systemName); 352222d268cbSEd Tanous return; 352322d268cbSEd Tanous } 352422d268cbSEd Tanous 35258e6c099aSJason M. Bills std::string diagnosticDataType; 35268e6c099aSJason M. Bills std::string oemDiagnosticDataType; 352715ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3528002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3529002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 35308e6c099aSJason M. Bills { 35318e6c099aSJason M. Bills return; 35328e6c099aSJason M. Bills } 35338e6c099aSJason M. Bills 35348e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 35358e6c099aSJason M. Bills { 353662598e31SEd Tanous BMCWEB_LOG_ERROR( 353762598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 35388e6c099aSJason M. Bills messages::actionParameterValueFormatError( 35398e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 35408e6c099aSJason M. Bills "CollectDiagnosticData"); 35418e6c099aSJason M. Bills return; 35428e6c099aSJason M. Bills } 35438e6c099aSJason M. Bills 3544c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3545c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3546c5a4c82aSJason M. Bills 3547c5a4c82aSJason M. Bills std::string iface; 3548c5a4c82aSJason M. Bills std::string method; 3549c5a4c82aSJason M. Bills std::string taskMatchStr; 3550c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3551c5a4c82aSJason M. Bills { 3552c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3553c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3554c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3555c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3556c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3557c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3558c5a4c82aSJason M. Bills } 3559c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3560c5a4c82aSJason M. Bills { 3561c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3562c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3563c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3564c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3565c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3566c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3567c5a4c82aSJason M. Bills } 3568c5a4c82aSJason M. Bills else 3569c5a4c82aSJason M. Bills { 357062598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 357162598e31SEd Tanous oemDiagnosticDataType); 3572c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3573002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3574002d39b4SEd Tanous "CollectDiagnosticData"); 3575c5a4c82aSJason M. Bills return; 3576c5a4c82aSJason M. Bills } 3577c5a4c82aSJason M. Bills 3578c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3579c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 35805e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 358198be3e39SEd Tanous const std::string&) mutable { 35821da66f75SEd Tanous if (ec) 35831da66f75SEd Tanous { 3584002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 35851da66f75SEd Tanous { 3586f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 35871da66f75SEd Tanous } 35884363d3b2SJason M. Bills else if (ec.value() == 35894363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 35904363d3b2SJason M. Bills { 3591002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3592002d39b4SEd Tanous "60"); 35934363d3b2SJason M. Bills } 35941da66f75SEd Tanous else 35951da66f75SEd Tanous { 3596f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35971da66f75SEd Tanous } 35981da66f75SEd Tanous return; 35991da66f75SEd Tanous } 3600002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 36018b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3602002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 36038b24275dSEd Tanous if (!ec2) 360466afe4faSJames Feist { 3605002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3606e5d5006bSJames Feist std::to_string(taskData->index))); 3607831d6b09SJames Feist taskData->state = "Completed"; 360866afe4faSJames Feist } 360932898ceaSJames Feist return task::completed; 361066afe4faSJames Feist }, 3611c5a4c82aSJason M. Bills taskMatchStr); 3612c5a4c82aSJason M. Bills 361346229577SJames Feist task->startTimer(std::chrono::minutes(5)); 361446229577SJames Feist task->populateResp(asyncResp->res); 361598be3e39SEd Tanous task->payload.emplace(std::move(payload)); 36161da66f75SEd Tanous }; 36178e6c099aSJason M. Bills 36181da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3619002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3620002d39b4SEd Tanous iface, method); 36217e860f15SJohn Edward Broadbent }); 36226eda7685SKenny L. Ku } 36236eda7685SKenny L. Ku 3624cb92c03bSAndrew Geissler /** 3625cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3626cb92c03bSAndrew Geissler */ 36277e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3628cb92c03bSAndrew Geissler { 3629cb92c03bSAndrew Geissler /** 3630cb92c03bSAndrew Geissler * Function handles POST method request. 3631cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3632cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3633cb92c03bSAndrew Geissler */ 36347e860f15SJohn Edward Broadbent 36350fda0f12SGeorge Liu BMCWEB_ROUTE( 36360fda0f12SGeorge Liu app, 363722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3638ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 36397e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 364045ca1b86SEd Tanous [&app](const crow::Request& req, 364122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 364222d268cbSEd Tanous const std::string& systemName) { 36433ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 364445ca1b86SEd Tanous { 364545ca1b86SEd Tanous return; 364645ca1b86SEd Tanous } 36477f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 36487f3e84a1SEd Tanous { 36497f3e84a1SEd Tanous // Option currently returns no systems. TBD 36507f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36517f3e84a1SEd Tanous systemName); 36527f3e84a1SEd Tanous return; 36537f3e84a1SEd Tanous } 365422d268cbSEd Tanous if (systemName != "system") 365522d268cbSEd Tanous { 365622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 365722d268cbSEd Tanous systemName); 365822d268cbSEd Tanous return; 365922d268cbSEd Tanous } 366062598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3661cb92c03bSAndrew Geissler 3662cb92c03bSAndrew Geissler // Process response from Logging service. 36635e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 366462598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3665cb92c03bSAndrew Geissler if (ec) 3666cb92c03bSAndrew Geissler { 3667cb92c03bSAndrew Geissler // TODO Handle for specific error code 366862598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3669cb92c03bSAndrew Geissler asyncResp->res.result( 3670cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3671cb92c03bSAndrew Geissler return; 3672cb92c03bSAndrew Geissler } 3673cb92c03bSAndrew Geissler 3674002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3675cb92c03bSAndrew Geissler }; 3676cb92c03bSAndrew Geissler 3677cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3678cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 36792c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3680cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3681cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 36827e860f15SJohn Edward Broadbent }); 3683cb92c03bSAndrew Geissler } 3684a3316fc6SZhikuiRen 3685a3316fc6SZhikuiRen /**************************************************** 3686a3316fc6SZhikuiRen * Redfish PostCode interfaces 3687a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3688a3316fc6SZhikuiRen ******************************************************/ 36897e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3690a3316fc6SZhikuiRen { 369122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3692ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3693002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3694002d39b4SEd Tanous [&app](const crow::Request& req, 369522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 369622d268cbSEd Tanous const std::string& systemName) { 36973ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 369845ca1b86SEd Tanous { 369945ca1b86SEd Tanous return; 370045ca1b86SEd Tanous } 37017f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37027f3e84a1SEd Tanous { 37037f3e84a1SEd Tanous // Option currently returns no systems. TBD 37047f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37057f3e84a1SEd Tanous systemName); 37067f3e84a1SEd Tanous return; 37077f3e84a1SEd Tanous } 370822d268cbSEd Tanous if (systemName != "system") 370922d268cbSEd Tanous { 371022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 371122d268cbSEd Tanous systemName); 371222d268cbSEd Tanous return; 371322d268cbSEd Tanous } 37141476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 37151476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 37161476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 37171476687dSEd Tanous "#LogService.v1_1_0.LogService"; 37181476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 37191476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3720ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 37211476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 37221476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 37231476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 37247c8c4058STejas Patil 37257c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 37262b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 37270fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 37287c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 37297c8c4058STejas Patil redfishDateTimeOffset.second; 37307c8c4058STejas Patil 3731a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 37327e860f15SJohn Edward Broadbent {"target", 37330fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 37347e860f15SJohn Edward Broadbent }); 3735a3316fc6SZhikuiRen } 3736a3316fc6SZhikuiRen 37377e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3738a3316fc6SZhikuiRen { 37390fda0f12SGeorge Liu BMCWEB_ROUTE( 37400fda0f12SGeorge Liu app, 374122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3742ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3743ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3744432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 37457e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 374645ca1b86SEd Tanous [&app](const crow::Request& req, 374722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 374822d268cbSEd Tanous const std::string& systemName) { 37493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 375045ca1b86SEd Tanous { 375145ca1b86SEd Tanous return; 375245ca1b86SEd Tanous } 37537f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37547f3e84a1SEd Tanous { 37557f3e84a1SEd Tanous // Option currently returns no systems. TBD 37567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37577f3e84a1SEd Tanous systemName); 37587f3e84a1SEd Tanous return; 37597f3e84a1SEd Tanous } 376022d268cbSEd Tanous if (systemName != "system") 376122d268cbSEd Tanous { 376222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 376322d268cbSEd Tanous systemName); 376422d268cbSEd Tanous return; 376522d268cbSEd Tanous } 376662598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3767a3316fc6SZhikuiRen 3768a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3769a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 37705e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3771a3316fc6SZhikuiRen if (ec) 3772a3316fc6SZhikuiRen { 3773a3316fc6SZhikuiRen // TODO Handle for specific error code 377462598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 377562598e31SEd Tanous ec); 3776002d39b4SEd Tanous asyncResp->res.result( 3777002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3778a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3779a3316fc6SZhikuiRen return; 3780a3316fc6SZhikuiRen } 3781a3316fc6SZhikuiRen }, 378215124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 378315124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3784a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 37857e860f15SJohn Edward Broadbent }); 3786a3316fc6SZhikuiRen } 3787a3316fc6SZhikuiRen 37886f284d24SJiaqing Zhao /** 37896f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 37906f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 37916f284d24SJiaqing Zhao * 37926f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 37936f284d24SJiaqing Zhao * @param[out] currentValue Current value 37946f284d24SJiaqing Zhao * @param[out] index Index value 37956f284d24SJiaqing Zhao * 37966f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 37976f284d24SJiaqing Zhao */ 37986f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 37996f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 38006f284d24SJiaqing Zhao { 38016f284d24SJiaqing Zhao std::vector<std::string> split; 380250ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 38036f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 38046f284d24SJiaqing Zhao { 38056f284d24SJiaqing Zhao return false; 38066f284d24SJiaqing Zhao } 38076f284d24SJiaqing Zhao 380884396af9SPatrick Williams auto start = std::next(split[0].begin()); 380984396af9SPatrick Williams auto end = split[0].end(); 381084396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 38116f284d24SJiaqing Zhao 381284396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 38136f284d24SJiaqing Zhao { 38146f284d24SJiaqing Zhao return false; 38156f284d24SJiaqing Zhao } 38166f284d24SJiaqing Zhao 381784396af9SPatrick Williams start = split[1].begin(); 381884396af9SPatrick Williams end = split[1].end(); 38196f284d24SJiaqing Zhao 382084396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 38216f284d24SJiaqing Zhao 382284396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 38236f284d24SJiaqing Zhao } 38246f284d24SJiaqing Zhao 38256f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3826ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 38276c9a279eSManojkiran Eda const boost::container::flat_map< 38286c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3829a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3830a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3831a3316fc6SZhikuiRen { 3832a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3833fffb8c1fSEd Tanous const registries::Message* message = 3834fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3835a3316fc6SZhikuiRen 3836a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3837a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 38386c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38396c9a279eSManojkiran Eda code : postcode) 3840a3316fc6SZhikuiRen { 3841a3316fc6SZhikuiRen currentCodeIndex++; 3842a3316fc6SZhikuiRen std::string postcodeEntryID = 3843a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3844a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3845a3316fc6SZhikuiRen 3846a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3847a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3848a3316fc6SZhikuiRen 3849a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3850a3316fc6SZhikuiRen { // already incremented 3851a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3852a3316fc6SZhikuiRen } 3853a3316fc6SZhikuiRen else 3854a3316fc6SZhikuiRen { 3855a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3856a3316fc6SZhikuiRen } 3857a3316fc6SZhikuiRen 3858a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3859a3316fc6SZhikuiRen // not fall between top and skip 3860a3316fc6SZhikuiRen if ((codeIndex == 0) && 3861a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3862a3316fc6SZhikuiRen { 3863a3316fc6SZhikuiRen continue; 3864a3316fc6SZhikuiRen } 3865a3316fc6SZhikuiRen 38664e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3867a3316fc6SZhikuiRen // currentIndex 3868a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3869a3316fc6SZhikuiRen { 3870a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3871a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3872a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3873a3316fc6SZhikuiRen continue; 3874a3316fc6SZhikuiRen } 3875a3316fc6SZhikuiRen 3876a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3877a3316fc6SZhikuiRen // index 3878a3316fc6SZhikuiRen 3879a3316fc6SZhikuiRen // Get the Created time from the timestamp 3880a3316fc6SZhikuiRen std::string entryTimeStr; 38812a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3882a3316fc6SZhikuiRen 3883a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3884a3316fc6SZhikuiRen std::ostringstream hexCode; 3885a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 38866c9a279eSManojkiran Eda << std::get<0>(code.second); 3887a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3888a3316fc6SZhikuiRen // Set Fixed -Point Notation 3889a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3890a3316fc6SZhikuiRen // Set precision to 4 digits 3891a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3892a3316fc6SZhikuiRen // Add double to stream 3893a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3894a3316fc6SZhikuiRen 38951e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 38961e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 38971e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 3898a3316fc6SZhikuiRen 38991e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 39001e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 39011e6deaf6SEd Tanous 39021e6deaf6SEd Tanous std::string msg = 39031e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 39041e6deaf6SEd Tanous if (msg.empty()) 3905a3316fc6SZhikuiRen { 39061e6deaf6SEd Tanous messages::internalError(asyncResp->res); 39071e6deaf6SEd Tanous return false; 3908a3316fc6SZhikuiRen } 3909a3316fc6SZhikuiRen 3910d4342a92STim Lee // Get Severity template from message registry 3911d4342a92STim Lee std::string severity; 3912d4342a92STim Lee if (message != nullptr) 3913d4342a92STim Lee { 39145f2b84eeSEd Tanous severity = message->messageSeverity; 3915d4342a92STim Lee } 3916d4342a92STim Lee 39176f284d24SJiaqing Zhao // Format entry 39186f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 39199c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3920ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 3921ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 3922ef4c65b7SEd Tanous postcodeEntryID); 392384afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 392484afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 392584afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 392684afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 39271e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 392884afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 392984afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 393084afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3931647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3932647b3cdcSGeorge Liu { 3933647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3934647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3935647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3936647b3cdcSGeorge Liu } 39376f284d24SJiaqing Zhao 39386f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 39396f284d24SJiaqing Zhao // that entry in this case 39406f284d24SJiaqing Zhao if (codeIndex != 0) 39416f284d24SJiaqing Zhao { 3942ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 39436f284d24SJiaqing Zhao return true; 3944a3316fc6SZhikuiRen } 39456f284d24SJiaqing Zhao 3946ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 3947b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 39486f284d24SJiaqing Zhao } 39496f284d24SJiaqing Zhao 39506f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 39516f284d24SJiaqing Zhao return false; 3952a3316fc6SZhikuiRen } 3953a3316fc6SZhikuiRen 3954ac106bf6SEd Tanous static void 3955ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39566f284d24SJiaqing Zhao const std::string& entryId) 3957a3316fc6SZhikuiRen { 39586f284d24SJiaqing Zhao uint16_t bootIndex = 0; 39596f284d24SJiaqing Zhao uint64_t codeIndex = 0; 39606f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 39616f284d24SJiaqing Zhao { 39626f284d24SJiaqing Zhao // Requested ID was not found 3963ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 39646f284d24SJiaqing Zhao return; 39656f284d24SJiaqing Zhao } 39666f284d24SJiaqing Zhao 39676f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 39686f284d24SJiaqing Zhao { 39696f284d24SJiaqing Zhao // 0 is an invalid index 3970ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 39716f284d24SJiaqing Zhao return; 39726f284d24SJiaqing Zhao } 39736f284d24SJiaqing Zhao 3974a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3975ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 39765e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 39776c9a279eSManojkiran Eda const boost::container::flat_map< 39786c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 39796c9a279eSManojkiran Eda postcode) { 3980a3316fc6SZhikuiRen if (ec) 3981a3316fc6SZhikuiRen { 398262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 3983ac106bf6SEd Tanous messages::internalError(asyncResp->res); 3984a3316fc6SZhikuiRen return; 3985a3316fc6SZhikuiRen } 3986a3316fc6SZhikuiRen 3987a3316fc6SZhikuiRen if (postcode.empty()) 3988a3316fc6SZhikuiRen { 3989ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 3990a3316fc6SZhikuiRen return; 3991a3316fc6SZhikuiRen } 3992a3316fc6SZhikuiRen 3993ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 39946f284d24SJiaqing Zhao { 3995ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 39966f284d24SJiaqing Zhao return; 39976f284d24SJiaqing Zhao } 3998a3316fc6SZhikuiRen }, 399915124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 400015124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4001a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4002a3316fc6SZhikuiRen bootIndex); 4003a3316fc6SZhikuiRen } 4004a3316fc6SZhikuiRen 4005ac106bf6SEd Tanous static void 4006ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4007ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4008ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4009a3316fc6SZhikuiRen { 4010a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4011ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 40125e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 40136c9a279eSManojkiran Eda const boost::container::flat_map< 40146c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 40156c9a279eSManojkiran Eda postcode) { 4016a3316fc6SZhikuiRen if (ec) 4017a3316fc6SZhikuiRen { 401862598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4019ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4020a3316fc6SZhikuiRen return; 4021a3316fc6SZhikuiRen } 4022a3316fc6SZhikuiRen 4023a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4024a3316fc6SZhikuiRen if (!postcode.empty()) 4025a3316fc6SZhikuiRen { 4026a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 40273648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4028a3316fc6SZhikuiRen { 402989492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 403089492a15SPatrick Williams entryCount) - 40313648c8beSEd Tanous entryCount; 4032a3316fc6SZhikuiRen uint64_t thisBootTop = 40333648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 40343648c8beSEd Tanous entryCount; 4035a3316fc6SZhikuiRen 4036ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4037ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4038a3316fc6SZhikuiRen } 4039ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4040a3316fc6SZhikuiRen } 4041a3316fc6SZhikuiRen 4042a3316fc6SZhikuiRen // continue to previous bootIndex 4043a3316fc6SZhikuiRen if (bootIndex < bootCount) 4044a3316fc6SZhikuiRen { 4045ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4046a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4047a3316fc6SZhikuiRen } 404881584abeSJiaqing Zhao else if (skip + top < endCount) 4049a3316fc6SZhikuiRen { 4050ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 40510fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 4052a3316fc6SZhikuiRen std::to_string(skip + top); 4053a3316fc6SZhikuiRen } 4054a3316fc6SZhikuiRen }, 405515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 405615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4057a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4058a3316fc6SZhikuiRen bootIndex); 4059a3316fc6SZhikuiRen } 4060a3316fc6SZhikuiRen 40618d1b46d7Szhanghch05 static void 4062ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40633648c8beSEd Tanous size_t skip, size_t top) 4064a3316fc6SZhikuiRen { 4065a3316fc6SZhikuiRen uint64_t entryCount = 0; 40661e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 40671e1e598dSJonathan Doman *crow::connections::systemBus, 40681e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 40691e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 40701e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4071ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 40721e1e598dSJonathan Doman const uint16_t bootCount) { 4073a3316fc6SZhikuiRen if (ec) 4074a3316fc6SZhikuiRen { 407562598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4076ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4077a3316fc6SZhikuiRen return; 4078a3316fc6SZhikuiRen } 4079ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 40801e1e598dSJonathan Doman }); 4081a3316fc6SZhikuiRen } 4082a3316fc6SZhikuiRen 40837e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4084a3316fc6SZhikuiRen { 40857e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 408622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4087ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 40887e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 408945ca1b86SEd Tanous [&app](const crow::Request& req, 409022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 409122d268cbSEd Tanous const std::string& systemName) { 4092c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4093c937d2bfSEd Tanous .canDelegateTop = true, 4094c937d2bfSEd Tanous .canDelegateSkip = true, 4095c937d2bfSEd Tanous }; 4096c937d2bfSEd Tanous query_param::Query delegatedQuery; 4097c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 40983ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 409945ca1b86SEd Tanous { 410045ca1b86SEd Tanous return; 410145ca1b86SEd Tanous } 41027f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 41037f3e84a1SEd Tanous { 41047f3e84a1SEd Tanous // Option currently returns no systems. TBD 41057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 41067f3e84a1SEd Tanous systemName); 41077f3e84a1SEd Tanous return; 41087f3e84a1SEd Tanous } 410922d268cbSEd Tanous 411022d268cbSEd Tanous if (systemName != "system") 411122d268cbSEd Tanous { 411222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 411322d268cbSEd Tanous systemName); 411422d268cbSEd Tanous return; 411522d268cbSEd Tanous } 4116a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4117a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4118a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4119a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4120a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4121a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4122a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4123a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4124a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 41253648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 41265143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 41273648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 41287e860f15SJohn Edward Broadbent }); 4129a3316fc6SZhikuiRen } 4130a3316fc6SZhikuiRen 4131647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4132647b3cdcSGeorge Liu { 41330fda0f12SGeorge Liu BMCWEB_ROUTE( 41340fda0f12SGeorge Liu app, 413522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4136647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4137647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 413845ca1b86SEd Tanous [&app](const crow::Request& req, 4139647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 414022d268cbSEd Tanous const std::string& systemName, 4141647b3cdcSGeorge Liu const std::string& postCodeID) { 41423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 414345ca1b86SEd Tanous { 414445ca1b86SEd Tanous return; 414545ca1b86SEd Tanous } 414672e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 414799351cd8SEd Tanous req.getHeaderValue("Accept"), 41484a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4149647b3cdcSGeorge Liu { 4150002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4151647b3cdcSGeorge Liu return; 4152647b3cdcSGeorge Liu } 41537f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 41547f3e84a1SEd Tanous { 41557f3e84a1SEd Tanous // Option currently returns no systems. TBD 41567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 41577f3e84a1SEd Tanous systemName); 41587f3e84a1SEd Tanous return; 41597f3e84a1SEd Tanous } 416022d268cbSEd Tanous if (systemName != "system") 416122d268cbSEd Tanous { 416222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 416322d268cbSEd Tanous systemName); 416422d268cbSEd Tanous return; 416522d268cbSEd Tanous } 4166647b3cdcSGeorge Liu 4167647b3cdcSGeorge Liu uint64_t currentValue = 0; 4168647b3cdcSGeorge Liu uint16_t index = 0; 4169647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4170647b3cdcSGeorge Liu { 4171002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4172647b3cdcSGeorge Liu return; 4173647b3cdcSGeorge Liu } 4174647b3cdcSGeorge Liu 4175647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4176647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 41775e7e2dc5SEd Tanous const boost::system::error_code& ec, 4178002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4179002d39b4SEd Tanous postcodes) { 4180647b3cdcSGeorge Liu if (ec.value() == EBADR) 4181647b3cdcSGeorge Liu { 4182002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4183002d39b4SEd Tanous postCodeID); 4184647b3cdcSGeorge Liu return; 4185647b3cdcSGeorge Liu } 4186647b3cdcSGeorge Liu if (ec) 4187647b3cdcSGeorge Liu { 418862598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4189647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4190647b3cdcSGeorge Liu return; 4191647b3cdcSGeorge Liu } 4192647b3cdcSGeorge Liu 4193647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4194002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4195647b3cdcSGeorge Liu { 419662598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4197002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4198002d39b4SEd Tanous postCodeID); 4199647b3cdcSGeorge Liu return; 4200647b3cdcSGeorge Liu } 4201647b3cdcSGeorge Liu 42029eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 420346ff87baSEd Tanous if (c.empty()) 4204647b3cdcSGeorge Liu { 420562598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4206002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4207002d39b4SEd Tanous postCodeID); 4208647b3cdcSGeorge Liu return; 4209647b3cdcSGeorge Liu } 421046ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 421146ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 421246ff87baSEd Tanous std::string_view strData(d, c.size()); 4213647b3cdcSGeorge Liu 4214d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4215647b3cdcSGeorge Liu "application/octet-stream"); 4216d9f6c621SEd Tanous asyncResp->res.addHeader( 4217d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4218002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4219647b3cdcSGeorge Liu }, 4220647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4221647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4222002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4223647b3cdcSGeorge Liu }); 4224647b3cdcSGeorge Liu } 4225647b3cdcSGeorge Liu 42267e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4227a3316fc6SZhikuiRen { 42287e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 422922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4230ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 42317e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 423245ca1b86SEd Tanous [&app](const crow::Request& req, 42337e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 423422d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 42353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 423645ca1b86SEd Tanous { 423745ca1b86SEd Tanous return; 423845ca1b86SEd Tanous } 42397f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42407f3e84a1SEd Tanous { 42417f3e84a1SEd Tanous // Option currently returns no systems. TBD 42427f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42437f3e84a1SEd Tanous systemName); 42447f3e84a1SEd Tanous return; 42457f3e84a1SEd Tanous } 424622d268cbSEd Tanous if (systemName != "system") 424722d268cbSEd Tanous { 424822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 424922d268cbSEd Tanous systemName); 425022d268cbSEd Tanous return; 425122d268cbSEd Tanous } 425222d268cbSEd Tanous 42536f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 42547e860f15SJohn Edward Broadbent }); 4255a3316fc6SZhikuiRen } 4256a3316fc6SZhikuiRen 42571da66f75SEd Tanous } // namespace redfish 4258