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> 45d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 46d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 471214b7e7SGunnar Mills 487a1dbc48SGeorge Liu #include <array> 49647b3cdcSGeorge Liu #include <charconv> 504418c7f0SJames Feist #include <filesystem> 5175710de2SXiaochao Ma #include <optional> 5226702d01SEd Tanous #include <span> 53cd225da8SJason M. Bills #include <string_view> 54abf2add6SEd Tanous #include <variant> 551da66f75SEd Tanous 561da66f75SEd Tanous namespace redfish 571da66f75SEd Tanous { 581da66f75SEd Tanous 595b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump"; 605b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump"; 615b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump"; 625b61b5e8SJason M. Bills constexpr char const* deleteAllInterface = 635b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 645b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface = 65424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 666eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface = 676eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 681da66f75SEd Tanous 698e31778eSAsmitha Karunanithi enum class DumpCreationProgress 708e31778eSAsmitha Karunanithi { 718e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 728e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 738e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 748e31778eSAsmitha Karunanithi }; 758e31778eSAsmitha Karunanithi 76f6150403SJames Feist namespace fs = std::filesystem; 771da66f75SEd Tanous 78cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 79cb92c03bSAndrew Geissler { 80d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 81d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 82d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 84cb92c03bSAndrew Geissler { 85cb92c03bSAndrew Geissler return "Critical"; 86cb92c03bSAndrew Geissler } 873174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 88d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 89d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 90cb92c03bSAndrew Geissler { 91cb92c03bSAndrew Geissler return "OK"; 92cb92c03bSAndrew Geissler } 933174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 94cb92c03bSAndrew Geissler { 95cb92c03bSAndrew Geissler return "Warning"; 96cb92c03bSAndrew Geissler } 97cb92c03bSAndrew Geissler return ""; 98cb92c03bSAndrew Geissler } 99cb92c03bSAndrew Geissler 1009017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1019017faf2SAbhishek Patel { 1029017faf2SAbhishek Patel std::optional<bool> notifyAction; 1039017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1049017faf2SAbhishek Patel { 1059017faf2SAbhishek Patel notifyAction = true; 1069017faf2SAbhishek Patel } 1079017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1089017faf2SAbhishek Patel { 1099017faf2SAbhishek Patel notifyAction = false; 1109017faf2SAbhishek Patel } 1119017faf2SAbhishek Patel 1129017faf2SAbhishek Patel return notifyAction; 1139017faf2SAbhishek Patel } 1149017faf2SAbhishek Patel 1157e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 11626ccae32SEd Tanous std::string_view field, 11739e77504SEd Tanous std::string_view& contents) 11816428a1aSJason M. Bills { 11916428a1aSJason M. Bills const char* data = nullptr; 12016428a1aSJason M. Bills size_t length = 0; 12116428a1aSJason M. Bills int ret = 0; 12216428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 12346ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 12446ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 12546ff87baSEd Tanous 12646ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 12716428a1aSJason M. Bills if (ret < 0) 12816428a1aSJason M. Bills { 12916428a1aSJason M. Bills return ret; 13016428a1aSJason M. Bills } 13139e77504SEd Tanous contents = std::string_view(data, length); 13216428a1aSJason M. Bills // Only use the content after the "=" character. 13381ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 13416428a1aSJason M. Bills return ret; 13516428a1aSJason M. Bills } 13616428a1aSJason M. Bills 1377e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 13826ccae32SEd Tanous std::string_view field, const int& base, 13926ccae32SEd Tanous long int& contents) 14016428a1aSJason M. Bills { 14116428a1aSJason M. Bills int ret = 0; 14239e77504SEd Tanous std::string_view metadata; 14316428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14416428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 14516428a1aSJason M. Bills if (ret < 0) 14616428a1aSJason M. Bills { 14716428a1aSJason M. Bills return ret; 14816428a1aSJason M. Bills } 149b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15016428a1aSJason M. Bills return ret; 15116428a1aSJason M. Bills } 15216428a1aSJason M. Bills 1537e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1547e860f15SJohn Edward Broadbent std::string& entryTimestamp) 155a3316fc6SZhikuiRen { 156a3316fc6SZhikuiRen int ret = 0; 157a3316fc6SZhikuiRen uint64_t timestamp = 0; 158a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 159a3316fc6SZhikuiRen if (ret < 0) 160a3316fc6SZhikuiRen { 161a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 162a3316fc6SZhikuiRen << strerror(-ret); 163a3316fc6SZhikuiRen return false; 164a3316fc6SZhikuiRen } 165e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1669c620e21SAsmitha Karunanithi return true; 167a3316fc6SZhikuiRen } 16850b8a43aSEd Tanous 1697e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 170e85d6b16SJason M. Bills const bool firstEntry = true) 17116428a1aSJason M. Bills { 17216428a1aSJason M. Bills int ret = 0; 17316428a1aSJason M. Bills static uint64_t prevTs = 0; 17416428a1aSJason M. Bills static int index = 0; 175e85d6b16SJason M. Bills if (firstEntry) 176e85d6b16SJason M. Bills { 177e85d6b16SJason M. Bills prevTs = 0; 178e85d6b16SJason M. Bills } 179e85d6b16SJason M. Bills 18016428a1aSJason M. Bills // Get the entry timestamp 18116428a1aSJason M. Bills uint64_t curTs = 0; 18216428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 18316428a1aSJason M. Bills if (ret < 0) 18416428a1aSJason M. Bills { 18516428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 18616428a1aSJason M. Bills << 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); 268c0bd5e4bSEd Tanous auto [ptr, ec] = std::from_chars( 269c0bd5e4bSEd Tanous indexStr.data(), indexStr.data() + indexStr.size(), 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 277c0bd5e4bSEd Tanous auto [ptr, ec] = 278c0bd5e4bSEd Tanous std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp); 279c0bd5e4bSEd Tanous if (ec != std::errc()) 28016428a1aSJason M. Bills { 2819db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 28216428a1aSJason M. Bills return false; 28316428a1aSJason M. Bills } 28416428a1aSJason M. Bills return true; 28516428a1aSJason M. Bills } 28616428a1aSJason M. Bills 28795820184SJason M. Bills static bool 28895820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 28995820184SJason M. Bills { 29095820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 29195820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 29295820184SJason M. Bills 29395820184SJason M. Bills // Loop through the directory looking for redfish log files 29495820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 29595820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 29695820184SJason M. Bills { 29795820184SJason M. Bills // If we find a redfish log file, save the path 29895820184SJason M. Bills std::string filename = dirEnt.path().filename(); 29911ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 30095820184SJason M. Bills { 30195820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 30295820184SJason M. Bills } 30395820184SJason M. Bills } 30495820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 30595820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 30695820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 30795820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 30895820184SJason M. Bills 30995820184SJason M. Bills return !redfishLogFiles.empty(); 31095820184SJason M. Bills } 31195820184SJason M. Bills 31268dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 31368dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 31468dd075aSAsmitha Karunanithi { 31568dd075aSAsmitha Karunanithi if (originatorType == 31668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 31768dd075aSAsmitha Karunanithi { 31868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 31968dd075aSAsmitha Karunanithi } 32068dd075aSAsmitha Karunanithi if (originatorType == 32168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 32268dd075aSAsmitha Karunanithi { 32368dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 32468dd075aSAsmitha Karunanithi } 32568dd075aSAsmitha Karunanithi if (originatorType == 32668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 32768dd075aSAsmitha Karunanithi { 32868dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 32968dd075aSAsmitha Karunanithi } 33068dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 33168dd075aSAsmitha Karunanithi } 33268dd075aSAsmitha Karunanithi 333aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3342d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 335c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 33668dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 337aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 338aefe3786SClaire Weinan { 339aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 340aefe3786SClaire Weinan { 341aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 342aefe3786SClaire Weinan { 343aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 344aefe3786SClaire Weinan { 345aefe3786SClaire Weinan if (propertyMap.first == "Status") 346aefe3786SClaire Weinan { 347aefe3786SClaire Weinan const auto* status = 348aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 349aefe3786SClaire Weinan if (status == nullptr) 350aefe3786SClaire Weinan { 351aefe3786SClaire Weinan messages::internalError(asyncResp->res); 352aefe3786SClaire Weinan break; 353aefe3786SClaire Weinan } 354aefe3786SClaire Weinan dumpStatus = *status; 355aefe3786SClaire Weinan } 356aefe3786SClaire Weinan } 357aefe3786SClaire Weinan } 358aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 359aefe3786SClaire Weinan { 360aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 361aefe3786SClaire Weinan { 362aefe3786SClaire Weinan if (propertyMap.first == "Size") 363aefe3786SClaire Weinan { 364aefe3786SClaire Weinan const auto* sizePtr = 365aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 366aefe3786SClaire Weinan if (sizePtr == nullptr) 367aefe3786SClaire Weinan { 368aefe3786SClaire Weinan messages::internalError(asyncResp->res); 369aefe3786SClaire Weinan break; 370aefe3786SClaire Weinan } 371aefe3786SClaire Weinan size = *sizePtr; 372aefe3786SClaire Weinan break; 373aefe3786SClaire Weinan } 374aefe3786SClaire Weinan } 375aefe3786SClaire Weinan } 376aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 377aefe3786SClaire Weinan { 378aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 379aefe3786SClaire Weinan { 380aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 381aefe3786SClaire Weinan { 382aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 383aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 384aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 385aefe3786SClaire Weinan { 386aefe3786SClaire Weinan messages::internalError(asyncResp->res); 387aefe3786SClaire Weinan break; 388aefe3786SClaire Weinan } 389c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 390aefe3786SClaire Weinan break; 391aefe3786SClaire Weinan } 392aefe3786SClaire Weinan } 393aefe3786SClaire Weinan } 39468dd075aSAsmitha Karunanithi else if (interfaceMap.first == 39568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 39668dd075aSAsmitha Karunanithi { 39768dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 39868dd075aSAsmitha Karunanithi { 39968dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 40068dd075aSAsmitha Karunanithi { 40168dd075aSAsmitha Karunanithi const std::string* id = 40268dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 40368dd075aSAsmitha Karunanithi if (id == nullptr) 40468dd075aSAsmitha Karunanithi { 40568dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 40668dd075aSAsmitha Karunanithi break; 40768dd075aSAsmitha Karunanithi } 40868dd075aSAsmitha Karunanithi originatorId = *id; 40968dd075aSAsmitha Karunanithi } 41068dd075aSAsmitha Karunanithi 41168dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 41268dd075aSAsmitha Karunanithi { 41368dd075aSAsmitha Karunanithi const std::string* type = 41468dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 41568dd075aSAsmitha Karunanithi if (type == nullptr) 41668dd075aSAsmitha Karunanithi { 41768dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 41868dd075aSAsmitha Karunanithi break; 41968dd075aSAsmitha Karunanithi } 42068dd075aSAsmitha Karunanithi 42168dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 42268dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 42368dd075aSAsmitha Karunanithi { 42468dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 42568dd075aSAsmitha Karunanithi break; 42668dd075aSAsmitha Karunanithi } 42768dd075aSAsmitha Karunanithi } 42868dd075aSAsmitha Karunanithi } 42968dd075aSAsmitha Karunanithi } 430aefe3786SClaire Weinan } 431aefe3786SClaire Weinan } 432aefe3786SClaire Weinan 43321ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 434fdd26906SClaire Weinan { 435fdd26906SClaire Weinan std::string entriesPath; 436fdd26906SClaire Weinan 437fdd26906SClaire Weinan if (dumpType == "BMC") 438fdd26906SClaire Weinan { 439fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 440fdd26906SClaire Weinan } 441fdd26906SClaire Weinan else if (dumpType == "FaultLog") 442fdd26906SClaire Weinan { 443fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 444fdd26906SClaire Weinan } 445fdd26906SClaire Weinan else if (dumpType == "System") 446fdd26906SClaire Weinan { 447fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 448fdd26906SClaire Weinan } 449fdd26906SClaire Weinan else 450fdd26906SClaire Weinan { 451fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 452fdd26906SClaire Weinan << dumpType; 453fdd26906SClaire Weinan } 454fdd26906SClaire Weinan 455fdd26906SClaire Weinan // Returns empty string on error 456fdd26906SClaire Weinan return entriesPath; 457fdd26906SClaire Weinan } 458fdd26906SClaire Weinan 4598d1b46d7Szhanghch05 inline void 4608d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4615cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4625cb1dd27SAsmitha Karunanithi { 463fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 464fdd26906SClaire Weinan if (entriesPath.empty()) 4655cb1dd27SAsmitha Karunanithi { 4665cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4675cb1dd27SAsmitha Karunanithi return; 4685cb1dd27SAsmitha Karunanithi } 4695cb1dd27SAsmitha Karunanithi 4705cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 471fdd26906SClaire Weinan [asyncResp, entriesPath, 4725e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 473711ac7a9SEd Tanous dbus::utility::ManagedObjectType& resp) { 4745cb1dd27SAsmitha Karunanithi if (ec) 4755cb1dd27SAsmitha Karunanithi { 4765cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4775cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4785cb1dd27SAsmitha Karunanithi return; 4795cb1dd27SAsmitha Karunanithi } 4805cb1dd27SAsmitha Karunanithi 481fdd26906SClaire Weinan // Remove ending slash 482fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 483fdd26906SClaire Weinan if (!odataIdStr.empty()) 484fdd26906SClaire Weinan { 485fdd26906SClaire Weinan odataIdStr.pop_back(); 486fdd26906SClaire Weinan } 487fdd26906SClaire Weinan 488fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 489fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 490fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 491fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 492fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = 493fdd26906SClaire Weinan "Collection of " + dumpType + " Dump Entries"; 494fdd26906SClaire Weinan 4955cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4965cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 497b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 498b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 499002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 5005cb1dd27SAsmitha Karunanithi 501002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 502002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 503002d39b4SEd Tanous r.first.filename()); 504565dfb6fSClaire Weinan }); 505565dfb6fSClaire Weinan 5065cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5075cb1dd27SAsmitha Karunanithi { 508b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5095cb1dd27SAsmitha Karunanithi { 5105cb1dd27SAsmitha Karunanithi continue; 5115cb1dd27SAsmitha Karunanithi } 512c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5135cb1dd27SAsmitha Karunanithi uint64_t size = 0; 51435440d18SAsmitha Karunanithi std::string dumpStatus; 51568dd075aSAsmitha Karunanithi std::string originatorId; 51668dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 51768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 518433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5192dfd18efSEd Tanous 5202dfd18efSEd Tanous std::string entryID = object.first.filename(); 5212dfd18efSEd Tanous if (entryID.empty()) 5225cb1dd27SAsmitha Karunanithi { 5235cb1dd27SAsmitha Karunanithi continue; 5245cb1dd27SAsmitha Karunanithi } 5255cb1dd27SAsmitha Karunanithi 526c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 52768dd075aSAsmitha Karunanithi originatorId, originatorType, 528aefe3786SClaire Weinan asyncResp); 5295cb1dd27SAsmitha Karunanithi 5300fda0f12SGeorge Liu if (dumpStatus != 5310fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 53235440d18SAsmitha Karunanithi !dumpStatus.empty()) 53335440d18SAsmitha Karunanithi { 53435440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 53535440d18SAsmitha Karunanithi continue; 53635440d18SAsmitha Karunanithi } 53735440d18SAsmitha Karunanithi 53868dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 539fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5405cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5415cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5425cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 543bbd80db8SClaire Weinan thisEntry["Created"] = 544bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5455cb1dd27SAsmitha Karunanithi 54668dd075aSAsmitha Karunanithi if (!originatorId.empty()) 54768dd075aSAsmitha Karunanithi { 54868dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 54968dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 55068dd075aSAsmitha Karunanithi } 55168dd075aSAsmitha Karunanithi 5525cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5535cb1dd27SAsmitha Karunanithi { 554d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 555d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 556fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 557fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5585cb1dd27SAsmitha Karunanithi } 5595cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5605cb1dd27SAsmitha Karunanithi { 561d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 562d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 563d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 564fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 565fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5665cb1dd27SAsmitha Karunanithi } 56735440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5685cb1dd27SAsmitha Karunanithi } 569002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5705cb1dd27SAsmitha Karunanithi }, 5715cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5725cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 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 5865cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 587fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 5885e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 58902cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5905cb1dd27SAsmitha Karunanithi if (ec) 5915cb1dd27SAsmitha Karunanithi { 5925cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5935cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5945cb1dd27SAsmitha Karunanithi return; 5955cb1dd27SAsmitha Karunanithi } 5965cb1dd27SAsmitha Karunanithi 597b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 598b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 599b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 600002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 601b47452b2SAsmitha Karunanithi 6029eb808c1SEd Tanous for (const auto& objectPath : resp) 6035cb1dd27SAsmitha Karunanithi { 604b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6055cb1dd27SAsmitha Karunanithi { 6065cb1dd27SAsmitha Karunanithi continue; 6075cb1dd27SAsmitha Karunanithi } 6085cb1dd27SAsmitha Karunanithi 6095cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 610c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6115cb1dd27SAsmitha Karunanithi uint64_t size = 0; 61235440d18SAsmitha Karunanithi std::string dumpStatus; 61368dd075aSAsmitha Karunanithi std::string originatorId; 61468dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 61568dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6165cb1dd27SAsmitha Karunanithi 617aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 61868dd075aSAsmitha Karunanithi timestampUs, originatorId, 61968dd075aSAsmitha Karunanithi originatorType, asyncResp); 6205cb1dd27SAsmitha Karunanithi 6210fda0f12SGeorge Liu if (dumpStatus != 6220fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 62335440d18SAsmitha Karunanithi !dumpStatus.empty()) 62435440d18SAsmitha Karunanithi { 62535440d18SAsmitha Karunanithi // Dump status is not Complete 62635440d18SAsmitha Karunanithi // return not found until status is changed to Completed 627d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 628d1bde9e5SKrzysztof Grobelny entryID); 62935440d18SAsmitha Karunanithi return; 63035440d18SAsmitha Karunanithi } 63135440d18SAsmitha Karunanithi 6325cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 63368dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 634fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6355cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6365cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6375cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 638bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 639bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6405cb1dd27SAsmitha Karunanithi 64168dd075aSAsmitha Karunanithi if (!originatorId.empty()) 64268dd075aSAsmitha Karunanithi { 64368dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 64468dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 64568dd075aSAsmitha Karunanithi } 64668dd075aSAsmitha Karunanithi 6475cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6485cb1dd27SAsmitha Karunanithi { 649d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 650d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 651fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 652fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6535cb1dd27SAsmitha Karunanithi } 6545cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6555cb1dd27SAsmitha Karunanithi { 656d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 657002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 658d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 659fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 660fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6615cb1dd27SAsmitha Karunanithi } 6625cb1dd27SAsmitha Karunanithi } 663e05aec50SEd Tanous if (!foundDumpEntry) 664b47452b2SAsmitha Karunanithi { 665b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 666b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 667b47452b2SAsmitha Karunanithi return; 668b47452b2SAsmitha Karunanithi } 6695cb1dd27SAsmitha Karunanithi }, 6705cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6715cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6725cb1dd27SAsmitha Karunanithi } 6735cb1dd27SAsmitha Karunanithi 6748d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6759878256fSStanley Chu const std::string& entryID, 676b47452b2SAsmitha Karunanithi const std::string& dumpType) 6775cb1dd27SAsmitha Karunanithi { 678002d39b4SEd Tanous auto respHandler = 6795e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 6805cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6815cb1dd27SAsmitha Karunanithi if (ec) 6825cb1dd27SAsmitha Karunanithi { 6833de8d8baSGeorge Liu if (ec.value() == EBADR) 6843de8d8baSGeorge Liu { 6853de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6863de8d8baSGeorge Liu return; 6873de8d8baSGeorge Liu } 6885cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 689fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6905cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6915cb1dd27SAsmitha Karunanithi return; 6925cb1dd27SAsmitha Karunanithi } 6935cb1dd27SAsmitha Karunanithi }; 6945cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6955cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 696b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 697b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 698b47452b2SAsmitha Karunanithi entryID, 6995cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7005cb1dd27SAsmitha Karunanithi } 7015cb1dd27SAsmitha Karunanithi 7028e31778eSAsmitha Karunanithi inline DumpCreationProgress 7038e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 704a43be80fSAsmitha Karunanithi { 7058e31778eSAsmitha Karunanithi if (status == 7068e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 7078e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 7088e31778eSAsmitha Karunanithi { 7098e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7108e31778eSAsmitha Karunanithi } 7118e31778eSAsmitha Karunanithi if (status == 7128e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 7138e31778eSAsmitha Karunanithi { 7148e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 7158e31778eSAsmitha Karunanithi } 7168e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7178e31778eSAsmitha Karunanithi } 7188e31778eSAsmitha Karunanithi 7198e31778eSAsmitha Karunanithi inline DumpCreationProgress 7208e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 7218e31778eSAsmitha Karunanithi { 7228e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 7238e31778eSAsmitha Karunanithi { 7248e31778eSAsmitha Karunanithi if (key == "Status") 7258e31778eSAsmitha Karunanithi { 7268e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 7278e31778eSAsmitha Karunanithi if (value == nullptr) 7288e31778eSAsmitha Karunanithi { 7298e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 7308e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 7318e31778eSAsmitha Karunanithi } 7328e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 7338e31778eSAsmitha Karunanithi } 7348e31778eSAsmitha Karunanithi } 7358e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7368e31778eSAsmitha Karunanithi } 7378e31778eSAsmitha Karunanithi 7388e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7398e31778eSAsmitha Karunanithi { 7408e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7418e31778eSAsmitha Karunanithi { 7428e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 7438e31778eSAsmitha Karunanithi } 7448e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7458e31778eSAsmitha Karunanithi { 7468e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 7478e31778eSAsmitha Karunanithi } 7488e31778eSAsmitha Karunanithi return ""; 7498e31778eSAsmitha Karunanithi } 7508e31778eSAsmitha Karunanithi 7518e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7528e31778eSAsmitha Karunanithi task::Payload&& payload, 7538e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7548e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7558e31778eSAsmitha Karunanithi { 7568e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7578e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7588e31778eSAsmitha Karunanithi 7598e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7608e31778eSAsmitha Karunanithi 7618e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7628e31778eSAsmitha Karunanithi { 7638e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 7648e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7658e31778eSAsmitha Karunanithi return; 7668e31778eSAsmitha Karunanithi } 7678e31778eSAsmitha Karunanithi 7688e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7698e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 7708e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 7715e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 7728e31778eSAsmitha Karunanithi const std::string& introspectXml) { 7738e31778eSAsmitha Karunanithi if (ec) 7748e31778eSAsmitha Karunanithi { 7758e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 7768e31778eSAsmitha Karunanithi << ec.message(); 7778e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7788e31778eSAsmitha Karunanithi return; 7798e31778eSAsmitha Karunanithi } 7808e31778eSAsmitha Karunanithi 7818e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 7828e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 7838e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 7848e31778eSAsmitha Karunanithi // Else, return task completed. 7858e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 7868e31778eSAsmitha Karunanithi 7878e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 7888e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 7898e31778eSAsmitha Karunanithi if (pRoot == nullptr) 7908e31778eSAsmitha Karunanithi { 7918e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 7928e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7938e31778eSAsmitha Karunanithi return; 7948e31778eSAsmitha Karunanithi } 7958e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 7968e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 7978e31778eSAsmitha Karunanithi 7988e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 7998e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 8008e31778eSAsmitha Karunanithi { 8018e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 8028e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 8038e31778eSAsmitha Karunanithi { 8048e31778eSAsmitha Karunanithi if (thisInterfaceName == 8058e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 8068e31778eSAsmitha Karunanithi { 8078e31778eSAsmitha Karunanithi interfaceNode = 8088e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 8098e31778eSAsmitha Karunanithi continue; 8108e31778eSAsmitha Karunanithi } 8118e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 8128e31778eSAsmitha Karunanithi break; 8138e31778eSAsmitha Karunanithi } 8148e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 8158e31778eSAsmitha Karunanithi } 8168e31778eSAsmitha Karunanithi 817a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 8188e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 8195e7e2dc5SEd Tanous const boost::system::error_code& err, sdbusplus::message_t& msg, 820a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 821cb13a392SEd Tanous if (err) 822cb13a392SEd Tanous { 8238e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8248e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8258e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 8266145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 8276145ed6fSAsmitha Karunanithi return task::completed; 828cb13a392SEd Tanous } 829b9d36b47SEd Tanous 8308e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 831a43be80fSAsmitha Karunanithi { 8328e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8338e31778eSAsmitha Karunanithi std::string prop; 8348e31778eSAsmitha Karunanithi msg.read(prop, values); 8358e31778eSAsmitha Karunanithi 8368e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8378e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8388e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8398e31778eSAsmitha Karunanithi { 8408e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8418e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8428e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8438e31778eSAsmitha Karunanithi return task::completed; 8448e31778eSAsmitha Karunanithi } 8458e31778eSAsmitha Karunanithi 8468e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8478e31778eSAsmitha Karunanithi { 8488e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8498e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 8508e31778eSAsmitha Karunanithi return !task::completed; 8518e31778eSAsmitha Karunanithi } 8528e31778eSAsmitha Karunanithi } 8538e31778eSAsmitha Karunanithi 854a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 855a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 856a43be80fSAsmitha Karunanithi 857a43be80fSAsmitha Karunanithi std::string headerLoc = 8588e31778eSAsmitha Karunanithi "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId); 859002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 860a43be80fSAsmitha Karunanithi 8618e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8628e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 863a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 864b47452b2SAsmitha Karunanithi return task::completed; 865a43be80fSAsmitha Karunanithi }, 8668e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 8678e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 8688e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 869a43be80fSAsmitha Karunanithi 8708e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 8718e31778eSAsmitha Karunanithi // requested dump will be collected. 8728e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 873a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 8748e31778eSAsmitha Karunanithi task->payload.emplace(payload); 8758e31778eSAsmitha Karunanithi }, 8768e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 8778e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 878a43be80fSAsmitha Karunanithi } 879a43be80fSAsmitha Karunanithi 8808d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8818d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 882a43be80fSAsmitha Karunanithi { 883fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 884fdd26906SClaire Weinan if (dumpPath.empty()) 885a43be80fSAsmitha Karunanithi { 886a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 887a43be80fSAsmitha Karunanithi return; 888a43be80fSAsmitha Karunanithi } 889a43be80fSAsmitha Karunanithi 890a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 891a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 892a43be80fSAsmitha Karunanithi 89315ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 894a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 895a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 896a43be80fSAsmitha Karunanithi { 897a43be80fSAsmitha Karunanithi return; 898a43be80fSAsmitha Karunanithi } 899a43be80fSAsmitha Karunanithi 900a43be80fSAsmitha Karunanithi if (dumpType == "System") 901a43be80fSAsmitha Karunanithi { 902a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 903a43be80fSAsmitha Karunanithi { 9044978b63fSJason M. Bills BMCWEB_LOG_ERROR 9054978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 906a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 907a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 908a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 909a43be80fSAsmitha Karunanithi return; 910a43be80fSAsmitha Karunanithi } 9113174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 912a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 913a43be80fSAsmitha Karunanithi { 914a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 915ace85d60SEd Tanous messages::internalError(asyncResp->res); 916a43be80fSAsmitha Karunanithi return; 917a43be80fSAsmitha Karunanithi } 9185907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 919a43be80fSAsmitha Karunanithi } 920a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 921a43be80fSAsmitha Karunanithi { 922a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 923a43be80fSAsmitha Karunanithi { 9240fda0f12SGeorge Liu BMCWEB_LOG_ERROR 9250fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 926a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 927a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 928a43be80fSAsmitha Karunanithi return; 929a43be80fSAsmitha Karunanithi } 9303174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 931a43be80fSAsmitha Karunanithi { 932a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 933a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 934ace85d60SEd Tanous messages::internalError(asyncResp->res); 935a43be80fSAsmitha Karunanithi return; 936a43be80fSAsmitha Karunanithi } 9375907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 9385907571dSAsmitha Karunanithi } 9395907571dSAsmitha Karunanithi else 9405907571dSAsmitha Karunanithi { 9415907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 9425907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9435907571dSAsmitha Karunanithi return; 944a43be80fSAsmitha Karunanithi } 945a43be80fSAsmitha Karunanithi 9468e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9478e31778eSAsmitha Karunanithi createDumpParamVec; 9488e31778eSAsmitha Karunanithi 949*f574a8e1SCarson Labrado if (req.session != nullptr) 950*f574a8e1SCarson Labrado { 95168dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 95268dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 95368dd075aSAsmitha Karunanithi req.session->clientIp); 95468dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 95568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 95668dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 957*f574a8e1SCarson Labrado } 95868dd075aSAsmitha Karunanithi 959a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9605e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 9615e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 9625e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 9638e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 964a43be80fSAsmitha Karunanithi if (ec) 965a43be80fSAsmitha Karunanithi { 966a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9675907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9685907571dSAsmitha Karunanithi if (dbusError == nullptr) 9695907571dSAsmitha Karunanithi { 9705907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9715907571dSAsmitha Karunanithi return; 9725907571dSAsmitha Karunanithi } 9735907571dSAsmitha Karunanithi 9745907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9755907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9765907571dSAsmitha Karunanithi if (std::string_view( 9775907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9785907571dSAsmitha Karunanithi dbusError->name) 9795907571dSAsmitha Karunanithi { 9805907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9815907571dSAsmitha Karunanithi return; 9825907571dSAsmitha Karunanithi } 9835907571dSAsmitha Karunanithi if (std::string_view( 9845907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9855907571dSAsmitha Karunanithi dbusError->name) 9865907571dSAsmitha Karunanithi { 9875907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9885907571dSAsmitha Karunanithi return; 9895907571dSAsmitha Karunanithi } 9905907571dSAsmitha Karunanithi if (std::string_view( 9915907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9925907571dSAsmitha Karunanithi dbusError->name) 9935907571dSAsmitha Karunanithi { 9945907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 9955907571dSAsmitha Karunanithi return; 9965907571dSAsmitha Karunanithi } 9975907571dSAsmitha Karunanithi // Other Dbus errors such as: 9985907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 9995907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 10005907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 10015907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 10025907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 10035907571dSAsmitha Karunanithi // back to the client. 1004a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1005a43be80fSAsmitha Karunanithi return; 1006a43be80fSAsmitha Karunanithi } 10078e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 10088e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1009a43be80fSAsmitha Karunanithi }, 1010b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 1011b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 1012b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 10138e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1014a43be80fSAsmitha Karunanithi } 1015a43be80fSAsmitha Karunanithi 10168d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10178d1b46d7Szhanghch05 const std::string& dumpType) 101880319af1SAsmitha Karunanithi { 1019b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 1020b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 10218d1b46d7Szhanghch05 10220d946211SClaire Weinan crow::connections::systemBus->async_method_call( 10230d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 102480319af1SAsmitha Karunanithi if (ec) 102580319af1SAsmitha Karunanithi { 10260d946211SClaire Weinan BMCWEB_LOG_ERROR << "clearDump resp_handler got error " << ec; 102780319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 102880319af1SAsmitha Karunanithi return; 102980319af1SAsmitha Karunanithi } 10300d946211SClaire Weinan }, 10310d946211SClaire Weinan "xyz.openbmc_project.Dump.Manager", 10320d946211SClaire Weinan "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 10330d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 103480319af1SAsmitha Karunanithi } 103580319af1SAsmitha Karunanithi 1036b9d36b47SEd Tanous inline static void 1037b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1038b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1039b9d36b47SEd Tanous std::string& logfile) 1040043a0536SJohnathan Mantey { 1041d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1042d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1043d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1044d1bde9e5SKrzysztof Grobelny 1045d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1046d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1047d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1048d1bde9e5SKrzysztof Grobelny 1049d1bde9e5SKrzysztof Grobelny if (!success) 1050043a0536SJohnathan Mantey { 1051d1bde9e5SKrzysztof Grobelny return; 1052043a0536SJohnathan Mantey } 1053d1bde9e5SKrzysztof Grobelny 1054d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1055043a0536SJohnathan Mantey { 1056d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1057d1bde9e5SKrzysztof Grobelny } 1058d1bde9e5SKrzysztof Grobelny 1059d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1060043a0536SJohnathan Mantey { 1061d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1062043a0536SJohnathan Mantey } 1063d1bde9e5SKrzysztof Grobelny 1064d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1065043a0536SJohnathan Mantey { 1066d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1067043a0536SJohnathan Mantey } 1068043a0536SJohnathan Mantey } 1069043a0536SJohnathan Mantey 10707e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10711da66f75SEd Tanous { 1072c4bf6374SJason M. Bills /** 1073c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1074c4bf6374SJason M. Bills */ 107522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1076ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1077002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1078002d39b4SEd Tanous [&app](const crow::Request& req, 107922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 108022d268cbSEd Tanous const std::string& systemName) { 10813ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1082c4bf6374SJason M. Bills { 108345ca1b86SEd Tanous return; 108445ca1b86SEd Tanous } 108522d268cbSEd Tanous if (systemName != "system") 108622d268cbSEd Tanous { 108722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 108822d268cbSEd Tanous systemName); 108922d268cbSEd Tanous return; 109022d268cbSEd Tanous } 109122d268cbSEd Tanous 10927e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10937e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1094c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1095c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1096c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1097029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 109845ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1099c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1100c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1101002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1102c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 11031476687dSEd Tanous nlohmann::json::object_t eventLog; 11041476687dSEd Tanous eventLog["@odata.id"] = 11051476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 11061476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 11075cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 11081476687dSEd Tanous nlohmann::json::object_t dumpLog; 1109002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 11101476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 1111c9bb6861Sraviteja-b #endif 1112c9bb6861Sraviteja-b 1113d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 11141476687dSEd Tanous nlohmann::json::object_t crashdump; 11151476687dSEd Tanous crashdump["@odata.id"] = 11161476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 11171476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 1118d53dd41fSJason M. Bills #endif 1119b7028ebfSSpencer Ku 1120b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 11211476687dSEd Tanous nlohmann::json::object_t hostlogger; 11221476687dSEd Tanous hostlogger["@odata.id"] = 11231476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 11241476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 1125b7028ebfSSpencer Ku #endif 1126c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1127c4bf6374SJason M. Bills logServiceArray.size(); 1128a3316fc6SZhikuiRen 11297a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 11307a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 11317a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11327a1dbc48SGeorge Liu "/", 0, interfaces, 11337a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1134b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1135b9d36b47SEd Tanous subtreePath) { 1136a3316fc6SZhikuiRen if (ec) 1137a3316fc6SZhikuiRen { 1138a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 1139a3316fc6SZhikuiRen return; 1140a3316fc6SZhikuiRen } 1141a3316fc6SZhikuiRen 114255f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1143a3316fc6SZhikuiRen { 1144a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1145a3316fc6SZhikuiRen { 114623a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1147a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1148613dabeaSEd Tanous nlohmann::json::object_t member; 1149613dabeaSEd Tanous member["@odata.id"] = 1150613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1151613dabeaSEd Tanous 1152613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 1153613dabeaSEd Tanous 115445ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 115523a21a1cSEd Tanous logServiceArrayLocal.size(); 1156a3316fc6SZhikuiRen return; 1157a3316fc6SZhikuiRen } 1158a3316fc6SZhikuiRen } 11597a1dbc48SGeorge Liu }); 11607e860f15SJohn Edward Broadbent }); 1161c4bf6374SJason M. Bills } 1162c4bf6374SJason M. Bills 11637e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1164c4bf6374SJason M. Bills { 116522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1166ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1167002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1168002d39b4SEd Tanous [&app](const crow::Request& req, 116922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 117022d268cbSEd Tanous const std::string& systemName) { 11713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117245ca1b86SEd Tanous { 117345ca1b86SEd Tanous return; 117445ca1b86SEd Tanous } 117522d268cbSEd Tanous if (systemName != "system") 117622d268cbSEd Tanous { 117722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 117822d268cbSEd Tanous systemName); 117922d268cbSEd Tanous return; 118022d268cbSEd Tanous } 1181c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1182029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1183c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1184c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1185c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1186002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1187c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1188c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11897c8c4058STejas Patil 11907c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11912b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11927c8c4058STejas Patil 11937c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 11947c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 11957c8c4058STejas Patil redfishDateTimeOffset.second; 11967c8c4058STejas Patil 11971476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 11981476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1199e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1200e7d6c8b2SGunnar Mills 12010fda0f12SGeorge Liu {"target", 12020fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 12037e860f15SJohn Edward Broadbent }); 1204489640c6SJason M. Bills } 1205489640c6SJason M. Bills 12067e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1207489640c6SJason M. Bills { 12084978b63fSJason M. Bills BMCWEB_ROUTE( 12094978b63fSJason M. Bills app, 121022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1211432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 12127e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 121345ca1b86SEd Tanous [&app](const crow::Request& req, 121422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 121522d268cbSEd Tanous const std::string& systemName) { 12163ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 121745ca1b86SEd Tanous { 121845ca1b86SEd Tanous return; 121945ca1b86SEd Tanous } 122022d268cbSEd Tanous if (systemName != "system") 122122d268cbSEd Tanous { 122222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 122322d268cbSEd Tanous systemName); 122422d268cbSEd Tanous return; 122522d268cbSEd Tanous } 1226489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1227489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1228489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1229489640c6SJason M. Bills { 1230489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1231489640c6SJason M. Bills { 1232489640c6SJason M. Bills std::error_code ec; 1233489640c6SJason M. Bills std::filesystem::remove(file, ec); 1234489640c6SJason M. Bills } 1235489640c6SJason M. Bills } 1236489640c6SJason M. Bills 1237489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1238489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 12395e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1240489640c6SJason M. Bills if (ec) 1241489640c6SJason M. Bills { 1242002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1243489640c6SJason M. Bills messages::internalError(asyncResp->res); 1244489640c6SJason M. Bills return; 1245489640c6SJason M. Bills } 1246489640c6SJason M. Bills 1247489640c6SJason M. Bills messages::success(asyncResp->res); 1248489640c6SJason M. Bills }, 1249489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1250002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1251002d39b4SEd Tanous "replace"); 12527e860f15SJohn Edward Broadbent }); 1253c4bf6374SJason M. Bills } 1254c4bf6374SJason M. Bills 1255ac992cdeSJason M. Bills enum class LogParseError 1256ac992cdeSJason M. Bills { 1257ac992cdeSJason M. Bills success, 1258ac992cdeSJason M. Bills parseFailed, 1259ac992cdeSJason M. Bills messageIdNotInRegistry, 1260ac992cdeSJason M. Bills }; 1261ac992cdeSJason M. Bills 1262ac992cdeSJason M. Bills static LogParseError 1263ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1264b5a76932SEd Tanous const std::string& logEntry, 1265de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1266c4bf6374SJason M. Bills { 126795820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1268cd225da8SJason M. Bills // First get the Timestamp 1269f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1270cd225da8SJason M. Bills if (space == std::string::npos) 127195820184SJason M. Bills { 1272ac992cdeSJason M. Bills return LogParseError::parseFailed; 127395820184SJason M. Bills } 1274cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1275cd225da8SJason M. Bills // Then get the log contents 1276f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1277cd225da8SJason M. Bills if (entryStart == std::string::npos) 1278cd225da8SJason M. Bills { 1279ac992cdeSJason M. Bills return LogParseError::parseFailed; 1280cd225da8SJason M. Bills } 1281cd225da8SJason M. Bills std::string_view entry(logEntry); 1282cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1283cd225da8SJason M. Bills // Use split to separate the entry into its fields 1284cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 128550ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1286cd225da8SJason M. Bills // We need at least a MessageId to be valid 128726f6976fSEd Tanous if (logEntryFields.empty()) 1288cd225da8SJason M. Bills { 1289ac992cdeSJason M. Bills return LogParseError::parseFailed; 1290cd225da8SJason M. Bills } 1291cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 129295820184SJason M. Bills 12934851d45dSJason M. Bills // Get the Message from the MessageRegistry 1294fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1295c4bf6374SJason M. Bills 129654417b02SSui Chen if (message == nullptr) 1297c4bf6374SJason M. Bills { 129854417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1299ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1300c4bf6374SJason M. Bills } 1301c4bf6374SJason M. Bills 130254417b02SSui Chen std::string msg = message->message; 130354417b02SSui Chen 130415a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 130526702d01SEd Tanous std::span<std::string> messageArgs; 130615a86ff6SJason M. Bills if (logEntryFields.size() > 1) 130715a86ff6SJason M. Bills { 130815a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 130915a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 131015a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 131115a86ff6SJason M. Bills if (!messageArgsStart.empty()) 131215a86ff6SJason M. Bills { 131315a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 131415a86ff6SJason M. Bills } 131515a86ff6SJason M. Bills 131623a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1317c4bf6374SJason M. Bills 13184851d45dSJason M. Bills // Fill the MessageArgs into the Message 131995820184SJason M. Bills int i = 0; 132095820184SJason M. Bills for (const std::string& messageArg : messageArgs) 13214851d45dSJason M. Bills { 132295820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 13234851d45dSJason M. Bills size_t argPos = msg.find(argStr); 13244851d45dSJason M. Bills if (argPos != std::string::npos) 13254851d45dSJason M. Bills { 132695820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 13274851d45dSJason M. Bills } 13284851d45dSJason M. Bills } 132915a86ff6SJason M. Bills } 13304851d45dSJason M. Bills 133195820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 133295820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 133395820184SJason M. Bills // between the '.' and the '+', so just remove them. 1334f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1335f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 133695820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1337c4bf6374SJason M. Bills { 133895820184SJason M. Bills timestamp.erase(dot, plus - dot); 1339c4bf6374SJason M. Bills } 1340c4bf6374SJason M. Bills 1341c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13429c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1343eddfc437SWilly Tu logEntryJson["@odata.id"] = crow::utility::urlFromPieces( 1344eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", "EventLog", 1345eddfc437SWilly Tu "Entries", logEntryID); 134684afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 134784afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 134884afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 134984afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 135084afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 135184afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 135284afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 135384afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1354ac992cdeSJason M. Bills return LogParseError::success; 1355c4bf6374SJason M. Bills } 1356c4bf6374SJason M. Bills 13577e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1358c4bf6374SJason M. Bills { 135922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13608b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1361002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1362002d39b4SEd Tanous [&app](const crow::Request& req, 136322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 136422d268cbSEd Tanous const std::string& systemName) { 1365c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1366c937d2bfSEd Tanous .canDelegateTop = true, 1367c937d2bfSEd Tanous .canDelegateSkip = true, 1368c937d2bfSEd Tanous }; 1369c937d2bfSEd Tanous query_param::Query delegatedQuery; 1370c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13713ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1372c4bf6374SJason M. Bills { 1373c4bf6374SJason M. Bills return; 1374c4bf6374SJason M. Bills } 137522d268cbSEd Tanous if (systemName != "system") 137622d268cbSEd Tanous { 137722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 137822d268cbSEd Tanous systemName); 137922d268cbSEd Tanous return; 138022d268cbSEd Tanous } 138122d268cbSEd Tanous 13825143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13833648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13843648c8beSEd Tanous 13857e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13867e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1387c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1388c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1389c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1390029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1391c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1392c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1393c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1394cb92c03bSAndrew Geissler 13954978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1396c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13977e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13987e860f15SJohn Edward Broadbent // entry 139995820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 140095820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1401b01bf299SEd Tanous uint64_t entryCount = 0; 1402cd225da8SJason M. Bills std::string logEntry; 140395820184SJason M. Bills 14047e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14057e860f15SJohn Edward Broadbent // backwards 1406002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1407002d39b4SEd Tanous it++) 1408c4bf6374SJason M. Bills { 1409cd225da8SJason M. Bills std::ifstream logStream(*it); 141095820184SJason M. Bills if (!logStream.is_open()) 1411c4bf6374SJason M. Bills { 1412c4bf6374SJason M. Bills continue; 1413c4bf6374SJason M. Bills } 1414c4bf6374SJason M. Bills 1415e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1416e85d6b16SJason M. Bills bool firstEntry = true; 141795820184SJason M. Bills while (std::getline(logStream, logEntry)) 141895820184SJason M. Bills { 1419c4bf6374SJason M. Bills std::string idStr; 1420e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1421c4bf6374SJason M. Bills { 1422c4bf6374SJason M. Bills continue; 1423c4bf6374SJason M. Bills } 1424e85d6b16SJason M. Bills firstEntry = false; 1425e85d6b16SJason M. Bills 1426de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1427ac992cdeSJason M. Bills LogParseError status = 1428ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1429ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1430ac992cdeSJason M. Bills { 1431ac992cdeSJason M. Bills continue; 1432ac992cdeSJason M. Bills } 1433ac992cdeSJason M. Bills if (status != LogParseError::success) 1434c4bf6374SJason M. Bills { 1435c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1436c4bf6374SJason M. Bills return; 1437c4bf6374SJason M. Bills } 1438de703c5dSJason M. Bills 1439de703c5dSJason M. Bills entryCount++; 1440de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1441de703c5dSJason M. Bills // start) and top (number of entries to display) 14423648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1443de703c5dSJason M. Bills { 1444de703c5dSJason M. Bills continue; 1445de703c5dSJason M. Bills } 1446de703c5dSJason M. Bills 1447de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1448c4bf6374SJason M. Bills } 144995820184SJason M. Bills } 1450c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14513648c8beSEd Tanous if (skip + top < entryCount) 1452c4bf6374SJason M. Bills { 1453c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14544978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14553648c8beSEd Tanous std::to_string(skip + top); 1456c4bf6374SJason M. Bills } 14577e860f15SJohn Edward Broadbent }); 1458897967deSJason M. Bills } 1459897967deSJason M. Bills 14607e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1461897967deSJason M. Bills { 14627e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 146322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1464ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 146645ca1b86SEd Tanous [&app](const crow::Request& req, 14677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 146822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 147045ca1b86SEd Tanous { 147145ca1b86SEd Tanous return; 147245ca1b86SEd Tanous } 147322d268cbSEd Tanous 147422d268cbSEd Tanous if (systemName != "system") 147522d268cbSEd Tanous { 147622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 147722d268cbSEd Tanous systemName); 147822d268cbSEd Tanous return; 147922d268cbSEd Tanous } 148022d268cbSEd Tanous 14817e860f15SJohn Edward Broadbent const std::string& targetID = param; 14828d1b46d7Szhanghch05 14837e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14847e860f15SJohn Edward Broadbent // entry to find the target entry 1485897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1486897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1487897967deSJason M. Bills std::string logEntry; 1488897967deSJason M. Bills 14897e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14907e860f15SJohn Edward Broadbent // backwards 1491002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1492002d39b4SEd Tanous it++) 1493897967deSJason M. Bills { 1494897967deSJason M. Bills std::ifstream logStream(*it); 1495897967deSJason M. Bills if (!logStream.is_open()) 1496897967deSJason M. Bills { 1497897967deSJason M. Bills continue; 1498897967deSJason M. Bills } 1499897967deSJason M. Bills 1500897967deSJason M. Bills // Reset the unique ID on the first entry 1501897967deSJason M. Bills bool firstEntry = true; 1502897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1503897967deSJason M. Bills { 1504897967deSJason M. Bills std::string idStr; 1505897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1506897967deSJason M. Bills { 1507897967deSJason M. Bills continue; 1508897967deSJason M. Bills } 1509897967deSJason M. Bills firstEntry = false; 1510897967deSJason M. Bills 1511897967deSJason M. Bills if (idStr == targetID) 1512897967deSJason M. Bills { 1513de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1514ac992cdeSJason M. Bills LogParseError status = 1515ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1516ac992cdeSJason M. Bills if (status != LogParseError::success) 1517897967deSJason M. Bills { 1518897967deSJason M. Bills messages::internalError(asyncResp->res); 1519897967deSJason M. Bills return; 1520897967deSJason M. Bills } 1521d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1522897967deSJason M. Bills return; 1523897967deSJason M. Bills } 1524897967deSJason M. Bills } 1525897967deSJason M. Bills } 1526897967deSJason M. Bills // Requested ID was not found 15279db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15287e860f15SJohn Edward Broadbent }); 152908a4e4b5SAnthony Wilson } 153008a4e4b5SAnthony Wilson 15317e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 153208a4e4b5SAnthony Wilson { 153322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1534ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1535002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1536002d39b4SEd Tanous [&app](const crow::Request& req, 153722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 153822d268cbSEd Tanous const std::string& systemName) { 15393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 154045ca1b86SEd Tanous { 154145ca1b86SEd Tanous return; 154245ca1b86SEd Tanous } 154322d268cbSEd Tanous if (systemName != "system") 154422d268cbSEd Tanous { 154522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 154622d268cbSEd Tanous systemName); 154722d268cbSEd Tanous return; 154822d268cbSEd Tanous } 154922d268cbSEd Tanous 15507e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15517e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 155208a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 155308a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 155408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 155508a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 155608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 155708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 155808a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 155908a4e4b5SAnthony Wilson 1560cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1561cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1562cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 15635e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1564914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1565cb92c03bSAndrew Geissler if (ec) 1566cb92c03bSAndrew Geissler { 1567cb92c03bSAndrew Geissler // TODO Handle for specific error code 1568cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1569002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1570cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1571cb92c03bSAndrew Geissler return; 1572cb92c03bSAndrew Geissler } 1573002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1574cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15759eb808c1SEd Tanous for (const auto& objectPath : resp) 1576cb92c03bSAndrew Geissler { 1577914e2d5dSEd Tanous const uint32_t* id = nullptr; 1578c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1579c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1580914e2d5dSEd Tanous const std::string* severity = nullptr; 1581914e2d5dSEd Tanous const std::string* message = nullptr; 1582914e2d5dSEd Tanous const std::string* filePath = nullptr; 15839c11a172SVijay Lobo const std::string* resolution = nullptr; 158475710de2SXiaochao Ma bool resolved = false; 15859017faf2SAbhishek Patel const std::string* notify = nullptr; 15869017faf2SAbhishek Patel 15879eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1588f86bb901SAdriana Kobylak { 1589f86bb901SAdriana Kobylak if (interfaceMap.first == 1590f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1591f86bb901SAdriana Kobylak { 1592002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1593cb92c03bSAndrew Geissler { 1594cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1595cb92c03bSAndrew Geissler { 1596002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1597cb92c03bSAndrew Geissler } 1598cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1599cb92c03bSAndrew Geissler { 1600002d39b4SEd Tanous timestamp = 1601002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16027e860f15SJohn Edward Broadbent } 1603002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 16047e860f15SJohn Edward Broadbent { 1605002d39b4SEd Tanous updateTimestamp = 1606002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 16077e860f15SJohn Edward Broadbent } 16087e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 16097e860f15SJohn Edward Broadbent { 16107e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 16117e860f15SJohn Edward Broadbent &propertyMap.second); 16127e860f15SJohn Edward Broadbent } 16139c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 16149c11a172SVijay Lobo { 16159c11a172SVijay Lobo resolution = std::get_if<std::string>( 16169c11a172SVijay Lobo &propertyMap.second); 16179c11a172SVijay Lobo } 16187e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 16197e860f15SJohn Edward Broadbent { 16207e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 16217e860f15SJohn Edward Broadbent &propertyMap.second); 16227e860f15SJohn Edward Broadbent } 16237e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 16247e860f15SJohn Edward Broadbent { 1625914e2d5dSEd Tanous const bool* resolveptr = 1626002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16277e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16287e860f15SJohn Edward Broadbent { 1629002d39b4SEd Tanous messages::internalError(asyncResp->res); 16307e860f15SJohn Edward Broadbent return; 16317e860f15SJohn Edward Broadbent } 16327e860f15SJohn Edward Broadbent resolved = *resolveptr; 16337e860f15SJohn Edward Broadbent } 16349017faf2SAbhishek Patel else if (propertyMap.first == 16359017faf2SAbhishek Patel "ServiceProviderNotify") 16369017faf2SAbhishek Patel { 16379017faf2SAbhishek Patel notify = std::get_if<std::string>( 16389017faf2SAbhishek Patel &propertyMap.second); 16399017faf2SAbhishek Patel if (notify == nullptr) 16409017faf2SAbhishek Patel { 16419017faf2SAbhishek Patel messages::internalError(asyncResp->res); 16429017faf2SAbhishek Patel return; 16439017faf2SAbhishek Patel } 16449017faf2SAbhishek Patel } 16457e860f15SJohn Edward Broadbent } 16467e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16477e860f15SJohn Edward Broadbent severity == nullptr) 16487e860f15SJohn Edward Broadbent { 16497e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16507e860f15SJohn Edward Broadbent return; 16517e860f15SJohn Edward Broadbent } 16527e860f15SJohn Edward Broadbent } 16537e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16547e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16557e860f15SJohn Edward Broadbent { 1656002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16577e860f15SJohn Edward Broadbent { 16587e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16597e860f15SJohn Edward Broadbent { 16607e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16617e860f15SJohn Edward Broadbent &propertyMap.second); 16627e860f15SJohn Edward Broadbent } 16637e860f15SJohn Edward Broadbent } 16647e860f15SJohn Edward Broadbent } 16657e860f15SJohn Edward Broadbent } 16667e860f15SJohn Edward Broadbent // Object path without the 16677e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16687e860f15SJohn Edward Broadbent // and continue. 16697e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1670c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1671c419c759SEd Tanous updateTimestamp == nullptr) 16727e860f15SJohn Edward Broadbent { 16737e860f15SJohn Edward Broadbent continue; 16747e860f15SJohn Edward Broadbent } 16757e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16767e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16779c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1678eddfc437SWilly Tu thisEntry["@odata.id"] = crow::utility::urlFromPieces( 1679eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", 1680eddfc437SWilly Tu "EventLog", "Entries", std::to_string(*id)); 16817e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16827e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16837e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16847e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16859c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16869c11a172SVijay Lobo { 16879c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16889c11a172SVijay Lobo } 16899017faf2SAbhishek Patel std::optional<bool> notifyAction = 16909017faf2SAbhishek Patel getProviderNotifyAction(*notify); 16919017faf2SAbhishek Patel if (notifyAction) 16929017faf2SAbhishek Patel { 16939017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 16949017faf2SAbhishek Patel } 16957e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16967e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16977e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16987e860f15SJohn Edward Broadbent thisEntry["Created"] = 16992b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 17007e860f15SJohn Edward Broadbent thisEntry["Modified"] = 17012b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 17027e860f15SJohn Edward Broadbent if (filePath != nullptr) 17037e860f15SJohn Edward Broadbent { 17047e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 17050fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 17067e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 17077e860f15SJohn Edward Broadbent } 17087e860f15SJohn Edward Broadbent } 1709002d39b4SEd Tanous std::sort( 1710002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1711002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 17127e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 17137e860f15SJohn Edward Broadbent }); 17147e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 17157e860f15SJohn Edward Broadbent entriesArray.size(); 17167e860f15SJohn Edward Broadbent }, 17177e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 17187e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 17197e860f15SJohn Edward Broadbent }); 17207e860f15SJohn Edward Broadbent } 17217e860f15SJohn Edward Broadbent 17227e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 17237e860f15SJohn Edward Broadbent { 17247e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 172522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1726ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1727002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1728002d39b4SEd Tanous [&app](const crow::Request& req, 17297e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 173022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17313ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17327e860f15SJohn Edward Broadbent { 173345ca1b86SEd Tanous return; 173445ca1b86SEd Tanous } 173522d268cbSEd Tanous if (systemName != "system") 173622d268cbSEd Tanous { 173722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 173822d268cbSEd Tanous systemName); 173922d268cbSEd Tanous return; 174022d268cbSEd Tanous } 174122d268cbSEd Tanous 17427e860f15SJohn Edward Broadbent std::string entryID = param; 17437e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17447e860f15SJohn Edward Broadbent 17457e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17467e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1747d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1748d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1749d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 17505e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1751b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17527e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17537e860f15SJohn Edward Broadbent { 1754d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1755d1bde9e5SKrzysztof Grobelny entryID); 17567e860f15SJohn Edward Broadbent return; 17577e860f15SJohn Edward Broadbent } 17587e860f15SJohn Edward Broadbent if (ec) 17597e860f15SJohn Edward Broadbent { 17600fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1761002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17627e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17637e860f15SJohn Edward Broadbent return; 17647e860f15SJohn Edward Broadbent } 1765914e2d5dSEd Tanous const uint32_t* id = nullptr; 1766c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1767c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1768914e2d5dSEd Tanous const std::string* severity = nullptr; 1769914e2d5dSEd Tanous const std::string* message = nullptr; 1770914e2d5dSEd Tanous const std::string* filePath = nullptr; 17719c11a172SVijay Lobo const std::string* resolution = nullptr; 17727e860f15SJohn Edward Broadbent bool resolved = false; 17739017faf2SAbhishek Patel const std::string* notify = nullptr; 17747e860f15SJohn Edward Broadbent 1775d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1776d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1777d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17789c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 17799017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 17809017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1781d1bde9e5SKrzysztof Grobelny 1782d1bde9e5SKrzysztof Grobelny if (!success) 178375710de2SXiaochao Ma { 178475710de2SXiaochao Ma messages::internalError(asyncResp->res); 178575710de2SXiaochao Ma return; 178675710de2SXiaochao Ma } 1787d1bde9e5SKrzysztof Grobelny 1788002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 17899017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 17909017faf2SAbhishek Patel notify == nullptr) 1791f86bb901SAdriana Kobylak { 1792ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1793271584abSEd Tanous return; 1794271584abSEd Tanous } 17959017faf2SAbhishek Patel 1796f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17979c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1798f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 1799eddfc437SWilly Tu crow::utility::urlFromPieces( 1800eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", 1801eddfc437SWilly Tu "EventLog", "Entries", std::to_string(*id)); 180245ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1803f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1804f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1805f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 18069017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 18079017faf2SAbhishek Patel if (notifyAction) 18089017faf2SAbhishek Patel { 18099017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 18109017faf2SAbhishek Patel *notifyAction; 18119017faf2SAbhishek Patel } 18129c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18139c11a172SVijay Lobo { 18149c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 18159c11a172SVijay Lobo } 1816f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1817f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1818f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1819f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 18202b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1821f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 18222b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1823f86bb901SAdriana Kobylak if (filePath != nullptr) 1824f86bb901SAdriana Kobylak { 1825f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1826e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1827e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1828f86bb901SAdriana Kobylak } 1829d1bde9e5SKrzysztof Grobelny }); 18307e860f15SJohn Edward Broadbent }); 1831336e96c6SChicago Duan 18327e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 183322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1834ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18357e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 183645ca1b86SEd Tanous [&app](const crow::Request& req, 18377e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 183822d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 18393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 184045ca1b86SEd Tanous { 184145ca1b86SEd Tanous return; 184245ca1b86SEd Tanous } 184322d268cbSEd Tanous if (systemName != "system") 184422d268cbSEd Tanous { 184522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 184622d268cbSEd Tanous systemName); 184722d268cbSEd Tanous return; 184822d268cbSEd Tanous } 184975710de2SXiaochao Ma std::optional<bool> resolved; 185075710de2SXiaochao Ma 185115ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 18527e860f15SJohn Edward Broadbent resolved)) 185375710de2SXiaochao Ma { 185475710de2SXiaochao Ma return; 185575710de2SXiaochao Ma } 185675710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 185775710de2SXiaochao Ma 185875710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 18595e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 186075710de2SXiaochao Ma if (ec) 186175710de2SXiaochao Ma { 186275710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 186375710de2SXiaochao Ma messages::internalError(asyncResp->res); 186475710de2SXiaochao Ma return; 186575710de2SXiaochao Ma } 186675710de2SXiaochao Ma }, 186775710de2SXiaochao Ma "xyz.openbmc_project.Logging", 186875710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 186975710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 187075710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1871168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18727e860f15SJohn Edward Broadbent }); 187375710de2SXiaochao Ma 18747e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 187522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1876ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1877ed398213SEd Tanous 1878002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1879002d39b4SEd Tanous [&app](const crow::Request& req, 1880002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 188122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18823ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1883336e96c6SChicago Duan { 188445ca1b86SEd Tanous return; 188545ca1b86SEd Tanous } 188622d268cbSEd Tanous if (systemName != "system") 188722d268cbSEd Tanous { 188822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 188922d268cbSEd Tanous systemName); 189022d268cbSEd Tanous return; 189122d268cbSEd Tanous } 1892336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1893336e96c6SChicago Duan 18947e860f15SJohn Edward Broadbent std::string entryID = param; 1895336e96c6SChicago Duan 1896336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1897336e96c6SChicago Duan 1898336e96c6SChicago Duan // Process response from Logging service. 1899002d39b4SEd Tanous auto respHandler = 19005e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec) { 1901002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1902336e96c6SChicago Duan if (ec) 1903336e96c6SChicago Duan { 19043de8d8baSGeorge Liu if (ec.value() == EBADR) 19053de8d8baSGeorge Liu { 190645ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 190745ca1b86SEd Tanous entryID); 19083de8d8baSGeorge Liu return; 19093de8d8baSGeorge Liu } 1910336e96c6SChicago Duan // TODO Handle for specific error code 19110fda0f12SGeorge Liu BMCWEB_LOG_ERROR 19120fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1913336e96c6SChicago Duan << ec; 1914336e96c6SChicago Duan asyncResp->res.result( 1915336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1916336e96c6SChicago Duan return; 1917336e96c6SChicago Duan } 1918336e96c6SChicago Duan 1919336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1920336e96c6SChicago Duan }; 1921336e96c6SChicago Duan 1922336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1923336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1924336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1925336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1926336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 19277e860f15SJohn Edward Broadbent }); 1928400fd1fbSAdriana Kobylak } 1929400fd1fbSAdriana Kobylak 19307e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1931400fd1fbSAdriana Kobylak { 19320fda0f12SGeorge Liu BMCWEB_ROUTE( 19330fda0f12SGeorge Liu app, 193422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1935ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 19367e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 193745ca1b86SEd Tanous [&app](const crow::Request& req, 19387e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 193922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19417e860f15SJohn Edward Broadbent { 194245ca1b86SEd Tanous return; 194345ca1b86SEd Tanous } 194499351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 194599351cd8SEd Tanous req.getHeaderValue("Accept"), 19464a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1947400fd1fbSAdriana Kobylak { 1948002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1949400fd1fbSAdriana Kobylak return; 1950400fd1fbSAdriana Kobylak } 195122d268cbSEd Tanous if (systemName != "system") 195222d268cbSEd Tanous { 195322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 195422d268cbSEd Tanous systemName); 195522d268cbSEd Tanous return; 195622d268cbSEd Tanous } 1957400fd1fbSAdriana Kobylak 19587e860f15SJohn Edward Broadbent std::string entryID = param; 1959400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1960400fd1fbSAdriana Kobylak 1961400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 19625e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1963400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1964400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1965400fd1fbSAdriana Kobylak { 1966002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1967002d39b4SEd Tanous entryID); 1968400fd1fbSAdriana Kobylak return; 1969400fd1fbSAdriana Kobylak } 1970400fd1fbSAdriana Kobylak if (ec) 1971400fd1fbSAdriana Kobylak { 1972400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1973400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1974400fd1fbSAdriana Kobylak return; 1975400fd1fbSAdriana Kobylak } 1976400fd1fbSAdriana Kobylak 1977400fd1fbSAdriana Kobylak int fd = -1; 1978400fd1fbSAdriana Kobylak fd = dup(unixfd); 1979400fd1fbSAdriana Kobylak if (fd == -1) 1980400fd1fbSAdriana Kobylak { 1981400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1982400fd1fbSAdriana Kobylak return; 1983400fd1fbSAdriana Kobylak } 1984400fd1fbSAdriana Kobylak 1985400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1986400fd1fbSAdriana Kobylak if (size == -1) 1987400fd1fbSAdriana Kobylak { 1988400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1989400fd1fbSAdriana Kobylak return; 1990400fd1fbSAdriana Kobylak } 1991400fd1fbSAdriana Kobylak 1992400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1993400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1994400fd1fbSAdriana Kobylak if (size > maxFileSize) 1995400fd1fbSAdriana Kobylak { 1996002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1997400fd1fbSAdriana Kobylak << maxFileSize; 1998400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1999400fd1fbSAdriana Kobylak return; 2000400fd1fbSAdriana Kobylak } 2001400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 2002400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 2003400fd1fbSAdriana Kobylak if (rc == -1) 2004400fd1fbSAdriana Kobylak { 2005400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2006400fd1fbSAdriana Kobylak return; 2007400fd1fbSAdriana Kobylak } 2008400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 2009400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 2010400fd1fbSAdriana Kobylak { 2011400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 2012400fd1fbSAdriana Kobylak return; 2013400fd1fbSAdriana Kobylak } 2014400fd1fbSAdriana Kobylak close(fd); 2015400fd1fbSAdriana Kobylak 2016400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 2017002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 2018400fd1fbSAdriana Kobylak 2019d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 2020400fd1fbSAdriana Kobylak "application/octet-stream"); 2021d9f6c621SEd Tanous asyncResp->res.addHeader( 2022d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 2023400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 2024400fd1fbSAdriana Kobylak }, 2025400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 2026400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 2027400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 20287e860f15SJohn Edward Broadbent }); 20291da66f75SEd Tanous } 20301da66f75SEd Tanous 2031b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2032b7028ebfSSpencer Ku 2033b7028ebfSSpencer Ku inline bool 2034b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2035b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2036b7028ebfSSpencer Ku { 2037b7028ebfSSpencer Ku std::error_code ec; 2038b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2039b7028ebfSSpencer Ku if (ec) 2040b7028ebfSSpencer Ku { 2041b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 2042b7028ebfSSpencer Ku return false; 2043b7028ebfSSpencer Ku } 2044b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2045b7028ebfSSpencer Ku { 2046b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2047b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2048b7028ebfSSpencer Ku // path 204911ba3979SEd Tanous if (filename.starts_with("log")) 2050b7028ebfSSpencer Ku { 2051b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2052b7028ebfSSpencer Ku } 2053b7028ebfSSpencer Ku } 2054b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2055b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2056b7028ebfSSpencer Ku // descending order. 2057b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2058b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2059b7028ebfSSpencer Ku 2060b7028ebfSSpencer Ku return true; 2061b7028ebfSSpencer Ku } 2062b7028ebfSSpencer Ku 206302cad96eSEd Tanous inline bool getHostLoggerEntries( 206402cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 206502cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2066b7028ebfSSpencer Ku { 2067b7028ebfSSpencer Ku GzFileReader logFile; 2068b7028ebfSSpencer Ku 2069b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2070b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2071b7028ebfSSpencer Ku { 2072b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2073b7028ebfSSpencer Ku { 2074b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2075b7028ebfSSpencer Ku return false; 2076b7028ebfSSpencer Ku } 2077b7028ebfSSpencer Ku } 2078b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2079b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2080b7028ebfSSpencer Ku if (!lastMessage.empty()) 2081b7028ebfSSpencer Ku { 2082b7028ebfSSpencer Ku logCount++; 2083b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2084b7028ebfSSpencer Ku { 2085b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2086b7028ebfSSpencer Ku } 2087b7028ebfSSpencer Ku } 2088b7028ebfSSpencer Ku return true; 2089b7028ebfSSpencer Ku } 2090b7028ebfSSpencer Ku 2091b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2092b7028ebfSSpencer Ku const std::string& msg, 20936d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2094b7028ebfSSpencer Ku { 2095b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20969c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2097eddfc437SWilly Tu logEntryJson["@odata.id"] = crow::utility::urlFromPieces( 2098eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", "HostLogger", 2099eddfc437SWilly Tu "Entries", logEntryID); 21006d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 21016d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 21026d6574c9SJason M. Bills logEntryJson["Message"] = msg; 21036d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 21046d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 21056d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2106b7028ebfSSpencer Ku } 2107b7028ebfSSpencer Ku 2108b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2109b7028ebfSSpencer Ku { 211022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2111b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 21121476687dSEd Tanous .methods(boost::beast::http::verb::get)( 21131476687dSEd Tanous [&app](const crow::Request& req, 211422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 211522d268cbSEd Tanous const std::string& systemName) { 21163ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 211745ca1b86SEd Tanous { 211845ca1b86SEd Tanous return; 211945ca1b86SEd Tanous } 212022d268cbSEd Tanous if (systemName != "system") 212122d268cbSEd Tanous { 212222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 212322d268cbSEd Tanous systemName); 212422d268cbSEd Tanous return; 212522d268cbSEd Tanous } 2126b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2127b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2128b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2129b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2130b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2131b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2132b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21331476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 21341476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2135b7028ebfSSpencer Ku }); 2136b7028ebfSSpencer Ku } 2137b7028ebfSSpencer Ku 2138b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2139b7028ebfSSpencer Ku { 2140b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 214122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2142b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2143002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2144002d39b4SEd Tanous [&app](const crow::Request& req, 214522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 214622d268cbSEd Tanous const std::string& systemName) { 2147c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2148c937d2bfSEd Tanous .canDelegateTop = true, 2149c937d2bfSEd Tanous .canDelegateSkip = true, 2150c937d2bfSEd Tanous }; 2151c937d2bfSEd Tanous query_param::Query delegatedQuery; 2152c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21533ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2154b7028ebfSSpencer Ku { 2155b7028ebfSSpencer Ku return; 2156b7028ebfSSpencer Ku } 215722d268cbSEd Tanous if (systemName != "system") 215822d268cbSEd Tanous { 215922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 216022d268cbSEd Tanous systemName); 216122d268cbSEd Tanous return; 216222d268cbSEd Tanous } 2163b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2164b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2165b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2166b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2167b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2168b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2169b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21700fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2171b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2172b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2173b7028ebfSSpencer Ku 2174b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2175b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2176b7028ebfSSpencer Ku { 2177b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2178b7028ebfSSpencer Ku return; 2179b7028ebfSSpencer Ku } 21803648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21813648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21825143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2183b7028ebfSSpencer Ku size_t logCount = 0; 2184b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2185b7028ebfSSpencer Ku // control by skip and top. 2186b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21873648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21883648c8beSEd Tanous logCount)) 2189b7028ebfSSpencer Ku { 2190b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2191b7028ebfSSpencer Ku return; 2192b7028ebfSSpencer Ku } 2193b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2194b7028ebfSSpencer Ku // log count 219526f6976fSEd Tanous if (logEntries.empty()) 2196b7028ebfSSpencer Ku { 2197b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2198b7028ebfSSpencer Ku return; 2199b7028ebfSSpencer Ku } 220026f6976fSEd Tanous if (!logEntries.empty()) 2201b7028ebfSSpencer Ku { 2202b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2203b7028ebfSSpencer Ku { 22046d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22053648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 22063648c8beSEd Tanous hostLogEntry); 22076d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2208b7028ebfSSpencer Ku } 2209b7028ebfSSpencer Ku 2210b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 22113648c8beSEd Tanous if (skip + top < logCount) 2212b7028ebfSSpencer Ku { 2213b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 22140fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 22153648c8beSEd Tanous std::to_string(skip + top); 2216b7028ebfSSpencer Ku } 2217b7028ebfSSpencer Ku } 2218b7028ebfSSpencer Ku }); 2219b7028ebfSSpencer Ku } 2220b7028ebfSSpencer Ku 2221b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2222b7028ebfSSpencer Ku { 2223b7028ebfSSpencer Ku BMCWEB_ROUTE( 222422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2225b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2226b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 222745ca1b86SEd Tanous [&app](const crow::Request& req, 2228b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 222922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 223145ca1b86SEd Tanous { 223245ca1b86SEd Tanous return; 223345ca1b86SEd Tanous } 223422d268cbSEd Tanous if (systemName != "system") 223522d268cbSEd Tanous { 223622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 223722d268cbSEd Tanous systemName); 223822d268cbSEd Tanous return; 223922d268cbSEd Tanous } 2240b7028ebfSSpencer Ku const std::string& targetID = param; 2241b7028ebfSSpencer Ku 2242b7028ebfSSpencer Ku uint64_t idInt = 0; 2243ca45aa3cSEd Tanous 2244ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2245ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2246ca45aa3cSEd Tanous 2247ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 22489db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 22499db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2250b7028ebfSSpencer Ku { 22519db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2252b7028ebfSSpencer Ku return; 2253b7028ebfSSpencer Ku } 2254b7028ebfSSpencer Ku 2255b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2256b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2257b7028ebfSSpencer Ku { 2258b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2259b7028ebfSSpencer Ku return; 2260b7028ebfSSpencer Ku } 2261b7028ebfSSpencer Ku 2262b7028ebfSSpencer Ku size_t logCount = 0; 22633648c8beSEd Tanous size_t top = 1; 2264b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2265b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2266b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2267b7028ebfSSpencer Ku // get that entry 2268002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2269002d39b4SEd Tanous logCount)) 2270b7028ebfSSpencer Ku { 2271b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2272b7028ebfSSpencer Ku return; 2273b7028ebfSSpencer Ku } 2274b7028ebfSSpencer Ku 2275b7028ebfSSpencer Ku if (!logEntries.empty()) 2276b7028ebfSSpencer Ku { 22776d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22786d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22796d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2280b7028ebfSSpencer Ku return; 2281b7028ebfSSpencer Ku } 2282b7028ebfSSpencer Ku 2283b7028ebfSSpencer Ku // Requested ID was not found 22849db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2285b7028ebfSSpencer Ku }); 2286b7028ebfSSpencer Ku } 2287b7028ebfSSpencer Ku 2288dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2289fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2290fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22911da66f75SEd Tanous { 22923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 229345ca1b86SEd Tanous { 229445ca1b86SEd Tanous return; 229545ca1b86SEd Tanous } 22967e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22977e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2298e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22991da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2300e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2301e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2302002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2303e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 23041da66f75SEd Tanous "Collection of LogServices for this Manager"; 2305002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2306c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2307fdd26906SClaire Weinan 2308c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2309613dabeaSEd Tanous nlohmann::json::object_t journal; 2310613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2311613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2312c4bf6374SJason M. Bills #endif 2313fdd26906SClaire Weinan 2314fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2315fdd26906SClaire Weinan 2316fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 231715912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 23187a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 23197a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 23207a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2321fdd26906SClaire Weinan [asyncResp]( 23227a1dbc48SGeorge Liu const boost::system::error_code& ec, 2323fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2324fdd26906SClaire Weinan if (ec) 2325fdd26906SClaire Weinan { 2326fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2327dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2328fdd26906SClaire Weinan << ec; 2329fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2330fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2331fdd26906SClaire Weinan return; 2332fdd26906SClaire Weinan } 2333fdd26906SClaire Weinan 2334fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2335fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2336fdd26906SClaire Weinan 2337fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2338fdd26906SClaire Weinan { 2339fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2340fdd26906SClaire Weinan { 2341613dabeaSEd Tanous nlohmann::json::object_t member; 2342613dabeaSEd Tanous member["@odata.id"] = 2343613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2344613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2345fdd26906SClaire Weinan } 2346fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2347fdd26906SClaire Weinan { 2348613dabeaSEd Tanous nlohmann::json::object_t member; 2349613dabeaSEd Tanous member["@odata.id"] = 2350613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2351613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2352fdd26906SClaire Weinan } 2353fdd26906SClaire Weinan } 2354fdd26906SClaire Weinan 2355e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2356fdd26906SClaire Weinan logServiceArrayLocal.size(); 23577a1dbc48SGeorge Liu }); 2358fdd26906SClaire Weinan #endif 2359fdd26906SClaire Weinan } 2360fdd26906SClaire Weinan 2361fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2362fdd26906SClaire Weinan { 2363fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2364fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2365fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2366dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2367e1f26343SJason M. Bills } 2368e1f26343SJason M. Bills 23697e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2370e1f26343SJason M. Bills { 23717e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2372ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23737e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 237445ca1b86SEd Tanous [&app](const crow::Request& req, 237545ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23777e860f15SJohn Edward Broadbent { 237845ca1b86SEd Tanous return; 237945ca1b86SEd Tanous } 2380e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2381e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23820f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23830f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2384002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2385002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2386ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2387e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23887c8c4058STejas Patil 23897c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23902b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2391002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23927c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23937c8c4058STejas Patil redfishDateTimeOffset.second; 23947c8c4058STejas Patil 23951476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23961476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23977e860f15SJohn Edward Broadbent }); 2398e1f26343SJason M. Bills } 2399e1f26343SJason M. Bills 24003a48b3a2SJason M. Bills static int 24013a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2402e1f26343SJason M. Bills sd_journal* journal, 24033a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2404e1f26343SJason M. Bills { 2405e1f26343SJason M. Bills // Get the Log Entry contents 2406e1f26343SJason M. Bills int ret = 0; 2407e1f26343SJason M. Bills 2408a8fe54f0SJason M. Bills std::string message; 2409a8fe54f0SJason M. Bills std::string_view syslogID; 2410a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2411a8fe54f0SJason M. Bills if (ret < 0) 2412a8fe54f0SJason M. Bills { 2413a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2414a8fe54f0SJason M. Bills << strerror(-ret); 2415a8fe54f0SJason M. Bills } 2416a8fe54f0SJason M. Bills if (!syslogID.empty()) 2417a8fe54f0SJason M. Bills { 2418a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2419a8fe54f0SJason M. Bills } 2420a8fe54f0SJason M. Bills 242139e77504SEd Tanous std::string_view msg; 242216428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2423e1f26343SJason M. Bills if (ret < 0) 2424e1f26343SJason M. Bills { 2425e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2426e1f26343SJason M. Bills return 1; 2427e1f26343SJason M. Bills } 2428a8fe54f0SJason M. Bills message += std::string(msg); 2429e1f26343SJason M. Bills 2430e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2431271584abSEd Tanous long int severity = 8; // Default to an invalid priority 243216428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2433e1f26343SJason M. Bills if (ret < 0) 2434e1f26343SJason M. Bills { 2435e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2436e1f26343SJason M. Bills } 2437e1f26343SJason M. Bills 2438e1f26343SJason M. Bills // Get the Created time from the timestamp 243916428a1aSJason M. Bills std::string entryTimeStr; 244016428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2441e1f26343SJason M. Bills { 244216428a1aSJason M. Bills return 1; 2443e1f26343SJason M. Bills } 2444e1f26343SJason M. Bills 2445e1f26343SJason M. Bills // Fill in the log entry with the gathered data 24469c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2447eddfc437SWilly Tu bmcJournalLogEntryJson["@odata.id"] = crow::utility::urlFromPieces( 2448eddfc437SWilly Tu "redfish", "v1", "Managers", "bmc", "LogServices", "Journal", "Entries", 2449eddfc437SWilly Tu bmcJournalLogEntryID); 245084afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 245184afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 245284afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 245384afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 245484afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2455738c1e61SPatrick Williams : severity <= 4 ? "Warning" 245684afc48bSJason M. Bills : "OK"; 245784afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 245884afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2459e1f26343SJason M. Bills return 0; 2460e1f26343SJason M. Bills } 2461e1f26343SJason M. Bills 24627e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2463e1f26343SJason M. Bills { 24647e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2465ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2466002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2467002d39b4SEd Tanous [&app](const crow::Request& req, 2468002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2469c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2470c937d2bfSEd Tanous .canDelegateTop = true, 2471c937d2bfSEd Tanous .canDelegateSkip = true, 2472c937d2bfSEd Tanous }; 2473c937d2bfSEd Tanous query_param::Query delegatedQuery; 2474c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24753ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2476193ad2faSJason M. Bills { 2477193ad2faSJason M. Bills return; 2478193ad2faSJason M. Bills } 24793648c8beSEd Tanous 24803648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24815143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24823648c8beSEd Tanous 24837e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24847e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2485e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2486e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24870f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24880f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2489e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2490e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2491e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24920fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2493e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2494e1f26343SJason M. Bills 24957e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24967e860f15SJohn Edward Broadbent // unique ID for each entry 2497e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2498e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2499e1f26343SJason M. Bills if (ret < 0) 2500e1f26343SJason M. Bills { 2501002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2502f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2503e1f26343SJason M. Bills return; 2504e1f26343SJason M. Bills } 25050fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 25060fda0f12SGeorge Liu journalTmp, sd_journal_close); 2507e1f26343SJason M. Bills journalTmp = nullptr; 2508b01bf299SEd Tanous uint64_t entryCount = 0; 2509e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2510e85d6b16SJason M. Bills bool firstEntry = true; 2511e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2512e1f26343SJason M. Bills { 2513193ad2faSJason M. Bills entryCount++; 25147e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 25157e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 25163648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2517193ad2faSJason M. Bills { 2518193ad2faSJason M. Bills continue; 2519193ad2faSJason M. Bills } 2520193ad2faSJason M. Bills 252116428a1aSJason M. Bills std::string idStr; 2522e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2523e1f26343SJason M. Bills { 2524e1f26343SJason M. Bills continue; 2525e1f26343SJason M. Bills } 2526e85d6b16SJason M. Bills firstEntry = false; 2527e85d6b16SJason M. Bills 25283a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2529c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2530c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2531e1f26343SJason M. Bills { 2532f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2533e1f26343SJason M. Bills return; 2534e1f26343SJason M. Bills } 25353a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2536e1f26343SJason M. Bills } 2537193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 25383648c8beSEd Tanous if (skip + top < entryCount) 2539193ad2faSJason M. Bills { 2540193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 25410fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 25423648c8beSEd Tanous std::to_string(skip + top); 2543193ad2faSJason M. Bills } 25447e860f15SJohn Edward Broadbent }); 2545e1f26343SJason M. Bills } 2546e1f26343SJason M. Bills 25477e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2548e1f26343SJason M. Bills { 25497e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 25507e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2551ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 25527e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 255345ca1b86SEd Tanous [&app](const crow::Request& req, 25547e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25557e860f15SJohn Edward Broadbent const std::string& entryID) { 25563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 255745ca1b86SEd Tanous { 255845ca1b86SEd Tanous return; 255945ca1b86SEd Tanous } 2560e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2561e1f26343SJason M. Bills uint64_t ts = 0; 2562271584abSEd Tanous uint64_t index = 0; 25638d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2564e1f26343SJason M. Bills { 256516428a1aSJason M. Bills return; 2566e1f26343SJason M. Bills } 2567e1f26343SJason M. Bills 2568e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2569e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2570e1f26343SJason M. Bills if (ret < 0) 2571e1f26343SJason M. Bills { 2572002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2573f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2574e1f26343SJason M. Bills return; 2575e1f26343SJason M. Bills } 2576002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2577002d39b4SEd Tanous journalTmp, sd_journal_close); 2578e1f26343SJason M. Bills journalTmp = nullptr; 25797e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25807e860f15SJohn Edward Broadbent // index tracking the unique ID 2581af07e3f5SJason M. Bills std::string idStr; 2582af07e3f5SJason M. Bills bool firstEntry = true; 2583e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25842056b6d1SManojkiran Eda if (ret < 0) 25852056b6d1SManojkiran Eda { 25862056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25872056b6d1SManojkiran Eda << strerror(-ret); 25882056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25892056b6d1SManojkiran Eda return; 25902056b6d1SManojkiran Eda } 2591271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2592e1f26343SJason M. Bills { 2593e1f26343SJason M. Bills sd_journal_next(journal.get()); 2594af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2595af07e3f5SJason M. Bills { 2596af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2597af07e3f5SJason M. Bills return; 2598af07e3f5SJason M. Bills } 2599af07e3f5SJason M. Bills firstEntry = false; 2600af07e3f5SJason M. Bills } 2601c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2602af07e3f5SJason M. Bills if (idStr != entryID) 2603c4bf6374SJason M. Bills { 26049db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2605c4bf6374SJason M. Bills return; 2606c4bf6374SJason M. Bills } 2607c4bf6374SJason M. Bills 26083a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2609c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 26103a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2611e1f26343SJason M. Bills { 2612f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2613e1f26343SJason M. Bills return; 2614e1f26343SJason M. Bills } 2615d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 26167e860f15SJohn Edward Broadbent }); 2617c9bb6861Sraviteja-b } 2618c9bb6861Sraviteja-b 2619fdd26906SClaire Weinan inline void 2620fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2621fdd26906SClaire Weinan const std::string& dumpType) 2622c9bb6861Sraviteja-b { 2623fdd26906SClaire Weinan std::string dumpPath; 2624fdd26906SClaire Weinan std::string overWritePolicy; 2625fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2626fdd26906SClaire Weinan 2627fdd26906SClaire Weinan if (dumpType == "BMC") 262845ca1b86SEd Tanous { 2629fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2630fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2631fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2632fdd26906SClaire Weinan } 2633fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2634fdd26906SClaire Weinan { 2635fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2636fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2637fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2638fdd26906SClaire Weinan } 2639fdd26906SClaire Weinan else if (dumpType == "System") 2640fdd26906SClaire Weinan { 2641fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2642fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2643fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2644fdd26906SClaire Weinan } 2645fdd26906SClaire Weinan else 2646fdd26906SClaire Weinan { 2647fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2648fdd26906SClaire Weinan << dumpType; 2649fdd26906SClaire Weinan messages::internalError(asyncResp->res); 265045ca1b86SEd Tanous return; 265145ca1b86SEd Tanous } 2652fdd26906SClaire Weinan 2653fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2654fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2655c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2656fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2657fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2658fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 26597c8c4058STejas Patil 26607c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 26612b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 26620fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 26637c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 26647c8c4058STejas Patil redfishDateTimeOffset.second; 26657c8c4058STejas Patil 2666fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2667fdd26906SClaire Weinan 2668fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2669fdd26906SClaire Weinan { 2670002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26711476687dSEd Tanous ["target"] = 2672fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2673fdd26906SClaire Weinan } 26740d946211SClaire Weinan 26750d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 26760d946211SClaire Weinan dbus::utility::getSubTreePaths( 26770d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 26780d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 26790d946211SClaire Weinan const boost::system::error_code& ec, 26800d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 26810d946211SClaire Weinan if (ec) 26820d946211SClaire Weinan { 26830d946211SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo respHandler got error " 26840d946211SClaire Weinan << ec; 26850d946211SClaire Weinan // Assume that getting an error simply means there are no dump 26860d946211SClaire Weinan // LogServices. Return without adding any error response. 26870d946211SClaire Weinan return; 26880d946211SClaire Weinan } 26890d946211SClaire Weinan 26900d946211SClaire Weinan const std::string dbusDumpPath = 26910d946211SClaire Weinan "/xyz/openbmc_project/dump/" + 26920d946211SClaire Weinan boost::algorithm::to_lower_copy(dumpType); 26930d946211SClaire Weinan 26940d946211SClaire Weinan for (const std::string& path : subTreePaths) 26950d946211SClaire Weinan { 26960d946211SClaire Weinan if (path == dbusDumpPath) 26970d946211SClaire Weinan { 26980d946211SClaire Weinan asyncResp->res 26990d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 27000d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 27010d946211SClaire Weinan break; 27020d946211SClaire Weinan } 27030d946211SClaire Weinan } 27040d946211SClaire Weinan }); 2705c9bb6861Sraviteja-b } 2706c9bb6861Sraviteja-b 2707fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2708fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2709fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 27107e860f15SJohn Edward Broadbent { 27113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 271245ca1b86SEd Tanous { 271345ca1b86SEd Tanous return; 271445ca1b86SEd Tanous } 2715fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2716fdd26906SClaire Weinan } 2717c9bb6861Sraviteja-b 271822d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 271922d268cbSEd Tanous crow::App& app, const crow::Request& req, 272022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 272122d268cbSEd Tanous const std::string& chassisId) 272222d268cbSEd Tanous { 272322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 272422d268cbSEd Tanous { 272522d268cbSEd Tanous return; 272622d268cbSEd Tanous } 272722d268cbSEd Tanous if (chassisId != "system") 272822d268cbSEd Tanous { 272922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 273022d268cbSEd Tanous return; 273122d268cbSEd Tanous } 273222d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 273322d268cbSEd Tanous } 273422d268cbSEd Tanous 2735fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2736fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2737fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2738fdd26906SClaire Weinan { 2739fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2740fdd26906SClaire Weinan { 2741fdd26906SClaire Weinan return; 2742fdd26906SClaire Weinan } 2743fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2744fdd26906SClaire Weinan } 2745fdd26906SClaire Weinan 274622d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 274722d268cbSEd Tanous crow::App& app, const crow::Request& req, 274822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 274922d268cbSEd Tanous const std::string& chassisId) 275022d268cbSEd Tanous { 275122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 275222d268cbSEd Tanous { 275322d268cbSEd Tanous return; 275422d268cbSEd Tanous } 275522d268cbSEd Tanous if (chassisId != "system") 275622d268cbSEd Tanous { 275722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 275822d268cbSEd Tanous return; 275922d268cbSEd Tanous } 276022d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 276122d268cbSEd Tanous } 276222d268cbSEd Tanous 2763fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2764fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2765fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2766fdd26906SClaire Weinan const std::string& dumpId) 2767fdd26906SClaire Weinan { 2768fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2769fdd26906SClaire Weinan { 2770fdd26906SClaire Weinan return; 2771fdd26906SClaire Weinan } 2772fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2773fdd26906SClaire Weinan } 277422d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 277522d268cbSEd Tanous crow::App& app, const crow::Request& req, 277622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 277722d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 277822d268cbSEd Tanous { 277922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 278022d268cbSEd Tanous { 278122d268cbSEd Tanous return; 278222d268cbSEd Tanous } 278322d268cbSEd Tanous if (chassisId != "system") 278422d268cbSEd Tanous { 278522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 278622d268cbSEd Tanous return; 278722d268cbSEd Tanous } 278822d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 278922d268cbSEd Tanous } 2790fdd26906SClaire Weinan 2791fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2792fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2793fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2794fdd26906SClaire Weinan const std::string& dumpId) 2795fdd26906SClaire Weinan { 2796fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2797fdd26906SClaire Weinan { 2798fdd26906SClaire Weinan return; 2799fdd26906SClaire Weinan } 2800fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2801fdd26906SClaire Weinan } 2802fdd26906SClaire Weinan 280322d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 280422d268cbSEd Tanous crow::App& app, const crow::Request& req, 280522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 280622d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 280722d268cbSEd Tanous { 280822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 280922d268cbSEd Tanous { 281022d268cbSEd Tanous return; 281122d268cbSEd Tanous } 281222d268cbSEd Tanous if (chassisId != "system") 281322d268cbSEd Tanous { 281422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 281522d268cbSEd Tanous return; 281622d268cbSEd Tanous } 281722d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 281822d268cbSEd Tanous } 281922d268cbSEd Tanous 2820fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2821fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2822fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2823fdd26906SClaire Weinan { 2824fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2825fdd26906SClaire Weinan { 2826fdd26906SClaire Weinan return; 2827fdd26906SClaire Weinan } 2828fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2829fdd26906SClaire Weinan } 2830fdd26906SClaire Weinan 283122d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 283222d268cbSEd Tanous crow::App& app, const crow::Request& req, 283322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 283422d268cbSEd Tanous const std::string& chassisId) 283522d268cbSEd Tanous { 283622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 283722d268cbSEd Tanous { 283822d268cbSEd Tanous return; 283922d268cbSEd Tanous } 284022d268cbSEd Tanous if (chassisId != "system") 284122d268cbSEd Tanous { 284222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 284322d268cbSEd Tanous return; 284422d268cbSEd Tanous } 284522d268cbSEd Tanous createDump(asyncResp, req, "System"); 284622d268cbSEd Tanous } 284722d268cbSEd Tanous 2848fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2849fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2850fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2851fdd26906SClaire Weinan { 2852fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2853fdd26906SClaire Weinan { 2854fdd26906SClaire Weinan return; 2855fdd26906SClaire Weinan } 2856fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2857fdd26906SClaire Weinan } 2858fdd26906SClaire Weinan 285922d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 286022d268cbSEd Tanous crow::App& app, const crow::Request& req, 286122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286222d268cbSEd Tanous const std::string& chassisId) 286322d268cbSEd Tanous { 286422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 286522d268cbSEd Tanous { 286622d268cbSEd Tanous return; 286722d268cbSEd Tanous } 286822d268cbSEd Tanous if (chassisId != "system") 286922d268cbSEd Tanous { 287022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 287122d268cbSEd Tanous return; 287222d268cbSEd Tanous } 287322d268cbSEd Tanous clearDump(asyncResp, "System"); 287422d268cbSEd Tanous } 287522d268cbSEd Tanous 2876fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2877fdd26906SClaire Weinan { 2878fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2879fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2880fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2881fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2882fdd26906SClaire Weinan } 2883fdd26906SClaire Weinan 2884fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2885fdd26906SClaire Weinan { 2886fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2887fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2888fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2889fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2890c9bb6861Sraviteja-b } 2891c9bb6861Sraviteja-b 28927e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2893c9bb6861Sraviteja-b { 28947e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28957e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2896ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2897fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2898fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2899fdd26906SClaire Weinan 29007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 29017e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2902ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2903fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2904fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2905c9bb6861Sraviteja-b } 2906c9bb6861Sraviteja-b 29077e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2908c9bb6861Sraviteja-b { 29090fda0f12SGeorge Liu BMCWEB_ROUTE( 29100fda0f12SGeorge Liu app, 29110fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2912ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29137e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2914fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2915fdd26906SClaire Weinan std::ref(app), "BMC")); 2916a43be80fSAsmitha Karunanithi } 2917a43be80fSAsmitha Karunanithi 29187e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 291980319af1SAsmitha Karunanithi { 29200fda0f12SGeorge Liu BMCWEB_ROUTE( 29210fda0f12SGeorge Liu app, 29220fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2923ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2924fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2925fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 292645ca1b86SEd Tanous } 2927fdd26906SClaire Weinan 2928fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2929fdd26906SClaire Weinan { 2930fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2931fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2932fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2933fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2934fdd26906SClaire Weinan } 2935fdd26906SClaire Weinan 2936fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2937fdd26906SClaire Weinan { 2938fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2939fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2940fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2941fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2942fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2943fdd26906SClaire Weinan } 2944fdd26906SClaire Weinan 2945fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2946fdd26906SClaire Weinan { 2947fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2948fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2949fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2950fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2951fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2952fdd26906SClaire Weinan 2953fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2954fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2955fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2956fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2957fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2958fdd26906SClaire Weinan } 2959fdd26906SClaire Weinan 2960fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2961fdd26906SClaire Weinan { 2962fdd26906SClaire Weinan BMCWEB_ROUTE( 2963fdd26906SClaire Weinan app, 2964fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2965fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2966fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2967fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 29685cb1dd27SAsmitha Karunanithi } 29695cb1dd27SAsmitha Karunanithi 29707e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 29715cb1dd27SAsmitha Karunanithi { 297222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2973ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 29746ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 297522d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 29765cb1dd27SAsmitha Karunanithi } 29775cb1dd27SAsmitha Karunanithi 29787e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 29797e860f15SJohn Edward Broadbent { 298022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2981ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 298222d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 298322d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 298422d268cbSEd Tanous std::ref(app))); 29855cb1dd27SAsmitha Karunanithi } 29865cb1dd27SAsmitha Karunanithi 29877e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 29885cb1dd27SAsmitha Karunanithi { 29897e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 299022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2991ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29926ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 299322d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29948d1b46d7Szhanghch05 29957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 299622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2997ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29986ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 299922d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 30005cb1dd27SAsmitha Karunanithi } 3001c9bb6861Sraviteja-b 30027e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3003c9bb6861Sraviteja-b { 30040fda0f12SGeorge Liu BMCWEB_ROUTE( 30050fda0f12SGeorge Liu app, 300622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3007ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 300822d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 300922d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 301022d268cbSEd Tanous std::ref(app))); 3011a43be80fSAsmitha Karunanithi } 3012a43be80fSAsmitha Karunanithi 30137e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3014a43be80fSAsmitha Karunanithi { 30150fda0f12SGeorge Liu BMCWEB_ROUTE( 30160fda0f12SGeorge Liu app, 301722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3018ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 30196ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 302022d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3021013487e5Sraviteja-b } 3022013487e5Sraviteja-b 30237e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 30241da66f75SEd Tanous { 30253946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30263946028dSAppaRao Puli // method for security reasons. 30271da66f75SEd Tanous /** 30281da66f75SEd Tanous * Functions triggers appropriate requests on DBus 30291da66f75SEd Tanous */ 303022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3031ed398213SEd Tanous // This is incorrect, should be: 3032ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3033432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3034002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3035002d39b4SEd Tanous [&app](const crow::Request& req, 303622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 303722d268cbSEd Tanous const std::string& systemName) { 30383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 303945ca1b86SEd Tanous { 304045ca1b86SEd Tanous return; 304145ca1b86SEd Tanous } 304222d268cbSEd Tanous if (systemName != "system") 304322d268cbSEd Tanous { 304422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 304522d268cbSEd Tanous systemName); 304622d268cbSEd Tanous return; 304722d268cbSEd Tanous } 304822d268cbSEd Tanous 30497e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 30507e860f15SJohn Edward Broadbent // SubRoute 30510f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3052424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3053e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 30548e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 30554f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 30564f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 30574f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 3058e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3059e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 30607c8c4058STejas Patil 30617c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 30622b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 30637c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 30647c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 30657c8c4058STejas Patil redfishDateTimeOffset.second; 30667c8c4058STejas Patil 30671476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3068eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", "system", 3069eddfc437SWilly Tu "LogServices", "Crashdump", "Entries"); 3070002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 30711476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3072002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 30731476687dSEd Tanous ["target"] = 30741476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 30757e860f15SJohn Edward Broadbent }); 30761da66f75SEd Tanous } 30771da66f75SEd Tanous 30787e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30795b61b5e8SJason M. Bills { 30800fda0f12SGeorge Liu BMCWEB_ROUTE( 30810fda0f12SGeorge Liu app, 308222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3083ed398213SEd Tanous // This is incorrect, should be: 3084ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3085432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30867e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 308745ca1b86SEd Tanous [&app](const crow::Request& req, 308822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 308922d268cbSEd Tanous const std::string& systemName) { 30903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 309145ca1b86SEd Tanous { 309245ca1b86SEd Tanous return; 309345ca1b86SEd Tanous } 309422d268cbSEd Tanous if (systemName != "system") 309522d268cbSEd Tanous { 309622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 309722d268cbSEd Tanous systemName); 309822d268cbSEd Tanous return; 309922d268cbSEd Tanous } 31005b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 31015e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3102cb13a392SEd Tanous const std::string&) { 31035b61b5e8SJason M. Bills if (ec) 31045b61b5e8SJason M. Bills { 31055b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 31065b61b5e8SJason M. Bills return; 31075b61b5e8SJason M. Bills } 31085b61b5e8SJason M. Bills messages::success(asyncResp->res); 31095b61b5e8SJason M. Bills }, 3110002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 31117e860f15SJohn Edward Broadbent }); 31125b61b5e8SJason M. Bills } 31135b61b5e8SJason M. Bills 31148d1b46d7Szhanghch05 static void 31158d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 31168d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3117e855dd28SJason M. Bills { 3118043a0536SJohnathan Mantey auto getStoredLogCallback = 3119b9d36b47SEd Tanous [asyncResp, logID, 31205e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3121b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3122e855dd28SJason M. Bills if (ec) 3123e855dd28SJason M. Bills { 3124e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 31251ddcf01aSJason M. Bills if (ec.value() == 31261ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 31271ddcf01aSJason M. Bills { 3128002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 31291ddcf01aSJason M. Bills } 31301ddcf01aSJason M. Bills else 31311ddcf01aSJason M. Bills { 3132e855dd28SJason M. Bills messages::internalError(asyncResp->res); 31331ddcf01aSJason M. Bills } 3134e855dd28SJason M. Bills return; 3135e855dd28SJason M. Bills } 3136043a0536SJohnathan Mantey 3137043a0536SJohnathan Mantey std::string timestamp{}; 3138043a0536SJohnathan Mantey std::string filename{}; 3139043a0536SJohnathan Mantey std::string logfile{}; 31402c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3141043a0536SJohnathan Mantey 3142043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3143e855dd28SJason M. Bills { 31449db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3145e855dd28SJason M. Bills return; 3146e855dd28SJason M. Bills } 3147e855dd28SJason M. Bills 3148043a0536SJohnathan Mantey std::string crashdumpURI = 3149e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3150043a0536SJohnathan Mantey logID + "/" + filename; 315184afc48bSJason M. Bills nlohmann::json::object_t logEntry; 31529c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3153eddfc437SWilly Tu logEntry["@odata.id"] = crow::utility::urlFromPieces( 3154eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", "Crashdump", 3155eddfc437SWilly Tu "Entries", logID); 315684afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 315784afc48bSJason M. Bills logEntry["Id"] = logID; 315884afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 315984afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 316084afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 316184afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 316284afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 31632b20ef6eSJason M. Bills 31642b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 31652b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 31662b20ef6eSJason M. Bills // directly 31672b20ef6eSJason M. Bills if (logEntryJson.is_array()) 31682b20ef6eSJason M. Bills { 31692b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 31702b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 31712b20ef6eSJason M. Bills logEntryJson.size(); 31722b20ef6eSJason M. Bills } 31732b20ef6eSJason M. Bills else 31742b20ef6eSJason M. Bills { 3175d405bb51SJason M. Bills logEntryJson.update(logEntry); 31762b20ef6eSJason M. Bills } 3177e855dd28SJason M. Bills }; 3178d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3179d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3180d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3181d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3182e855dd28SJason M. Bills } 3183e855dd28SJason M. Bills 31847e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31851da66f75SEd Tanous { 31863946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31873946028dSAppaRao Puli // method for security reasons. 31881da66f75SEd Tanous /** 31891da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31901da66f75SEd Tanous */ 31917e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 319222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3193ed398213SEd Tanous // This is incorrect, should be. 3194ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3195432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3196002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3197002d39b4SEd Tanous [&app](const crow::Request& req, 319822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 319922d268cbSEd Tanous const std::string& systemName) { 32003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 320145ca1b86SEd Tanous { 320245ca1b86SEd Tanous return; 320345ca1b86SEd Tanous } 320422d268cbSEd Tanous if (systemName != "system") 320522d268cbSEd Tanous { 320622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 320722d268cbSEd Tanous systemName); 320822d268cbSEd Tanous return; 320922d268cbSEd Tanous } 321022d268cbSEd Tanous 32117a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 32127a1dbc48SGeorge Liu crashdumpInterface}; 32137a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 32147a1dbc48SGeorge Liu "/", 0, interfaces, 32157a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 32162b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 32171da66f75SEd Tanous if (ec) 32181da66f75SEd Tanous { 32191da66f75SEd Tanous if (ec.value() != 32201da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 32211da66f75SEd Tanous { 32221da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 32231da66f75SEd Tanous << ec.message(); 3224f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32251da66f75SEd Tanous return; 32261da66f75SEd Tanous } 32271da66f75SEd Tanous } 3228e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32291da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 32300f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3231424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3232002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3233e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3234424c4176SJason M. Bills "Collection of Crashdump Entries"; 3235002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3236a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 32372b20ef6eSJason M. Bills 32382b20ef6eSJason M. Bills for (const std::string& path : resp) 32391da66f75SEd Tanous { 32402b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3241e855dd28SJason M. Bills // Get the log ID 32422b20ef6eSJason M. Bills std::string logID = objPath.filename(); 32432b20ef6eSJason M. Bills if (logID.empty()) 32441da66f75SEd Tanous { 3245e855dd28SJason M. Bills continue; 32461da66f75SEd Tanous } 3247e855dd28SJason M. Bills // Add the log entry to the array 32482b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 32492b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 32501da66f75SEd Tanous } 32517a1dbc48SGeorge Liu }); 32527e860f15SJohn Edward Broadbent }); 32531da66f75SEd Tanous } 32541da66f75SEd Tanous 32557e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 32561da66f75SEd Tanous { 32573946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32583946028dSAppaRao Puli // method for security reasons. 32591da66f75SEd Tanous 32607e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 326122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3262ed398213SEd Tanous // this is incorrect, should be 3263ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3264432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 326645ca1b86SEd Tanous [&app](const crow::Request& req, 32677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 326822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 32693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 327045ca1b86SEd Tanous { 327145ca1b86SEd Tanous return; 327245ca1b86SEd Tanous } 327322d268cbSEd Tanous if (systemName != "system") 327422d268cbSEd Tanous { 327522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 327622d268cbSEd Tanous systemName); 327722d268cbSEd Tanous return; 327822d268cbSEd Tanous } 32797e860f15SJohn Edward Broadbent const std::string& logID = param; 3280e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32817e860f15SJohn Edward Broadbent }); 3282e855dd28SJason M. Bills } 3283e855dd28SJason M. Bills 32847e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3285e855dd28SJason M. Bills { 32863946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32873946028dSAppaRao Puli // method for security reasons. 32887e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32897e860f15SJohn Edward Broadbent app, 329022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3291ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32927e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3293a4ce114aSNan Zhou [](const crow::Request& req, 32947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 329522d268cbSEd Tanous const std::string& systemName, const std::string& logID, 329622d268cbSEd Tanous const std::string& fileName) { 32972a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32982a9beeedSShounak Mitra // Redfish resource. 329922d268cbSEd Tanous 330022d268cbSEd Tanous if (systemName != "system") 330122d268cbSEd Tanous { 330222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 330322d268cbSEd Tanous systemName); 330422d268cbSEd Tanous return; 330522d268cbSEd Tanous } 330622d268cbSEd Tanous 3307043a0536SJohnathan Mantey auto getStoredLogCallback = 330839662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 33095e7e2dc5SEd Tanous const boost::system::error_code& ec, 3310002d39b4SEd Tanous const std::vector< 3311002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 33127e860f15SJohn Edward Broadbent resp) { 33131da66f75SEd Tanous if (ec) 33141da66f75SEd Tanous { 3315002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3316f12894f8SJason M. Bills messages::internalError(asyncResp->res); 33171da66f75SEd Tanous return; 33181da66f75SEd Tanous } 3319e855dd28SJason M. Bills 3320043a0536SJohnathan Mantey std::string dbusFilename{}; 3321043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3322043a0536SJohnathan Mantey std::string dbusFilepath{}; 3323043a0536SJohnathan Mantey 3324002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3325002d39b4SEd Tanous dbusFilepath); 3326043a0536SJohnathan Mantey 3327043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3328043a0536SJohnathan Mantey dbusFilepath.empty()) 33291da66f75SEd Tanous { 33309db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33311da66f75SEd Tanous return; 33321da66f75SEd Tanous } 3333e855dd28SJason M. Bills 3334043a0536SJohnathan Mantey // Verify the file name parameter is correct 3335043a0536SJohnathan Mantey if (fileName != dbusFilename) 3336043a0536SJohnathan Mantey { 33379db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3338043a0536SJohnathan Mantey return; 3339043a0536SJohnathan Mantey } 3340043a0536SJohnathan Mantey 3341043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3342043a0536SJohnathan Mantey { 33439db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3344043a0536SJohnathan Mantey return; 3345043a0536SJohnathan Mantey } 3346002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3347002d39b4SEd Tanous asyncResp->res.body() = 3348002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3349043a0536SJohnathan Mantey 33507e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 33517e860f15SJohn Edward Broadbent // from a browser 3352d9f6c621SEd Tanous asyncResp->res.addHeader( 3353d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 33541da66f75SEd Tanous }; 3355d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3356d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3357d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3358d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 33597e860f15SJohn Edward Broadbent }); 33601da66f75SEd Tanous } 33611da66f75SEd Tanous 3362c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3363c5a4c82aSJason M. Bills { 3364c5a4c82aSJason M. Bills onDemand, 3365c5a4c82aSJason M. Bills telemetry, 3366c5a4c82aSJason M. Bills invalid, 3367c5a4c82aSJason M. Bills }; 3368c5a4c82aSJason M. Bills 336926ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3370c5a4c82aSJason M. Bills { 3371c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3372c5a4c82aSJason M. Bills { 3373c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3374c5a4c82aSJason M. Bills } 3375c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3376c5a4c82aSJason M. Bills { 3377c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3378c5a4c82aSJason M. Bills } 3379c5a4c82aSJason M. Bills 3380c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3381c5a4c82aSJason M. Bills } 3382c5a4c82aSJason M. Bills 33837e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33841da66f75SEd Tanous { 33853946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33863946028dSAppaRao Puli // method for security reasons. 33870fda0f12SGeorge Liu BMCWEB_ROUTE( 33880fda0f12SGeorge Liu app, 338922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3390ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3391ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3392432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3393002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3394002d39b4SEd Tanous [&app](const crow::Request& req, 339522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 339622d268cbSEd Tanous const std::string& systemName) { 33973ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 339845ca1b86SEd Tanous { 339945ca1b86SEd Tanous return; 340045ca1b86SEd Tanous } 340122d268cbSEd Tanous 340222d268cbSEd Tanous if (systemName != "system") 340322d268cbSEd Tanous { 340422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 340522d268cbSEd Tanous systemName); 340622d268cbSEd Tanous return; 340722d268cbSEd Tanous } 340822d268cbSEd Tanous 34098e6c099aSJason M. Bills std::string diagnosticDataType; 34108e6c099aSJason M. Bills std::string oemDiagnosticDataType; 341115ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3412002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3413002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 34148e6c099aSJason M. Bills { 34158e6c099aSJason M. Bills return; 34168e6c099aSJason M. Bills } 34178e6c099aSJason M. Bills 34188e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 34198e6c099aSJason M. Bills { 34208e6c099aSJason M. Bills BMCWEB_LOG_ERROR 34218e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 34228e6c099aSJason M. Bills messages::actionParameterValueFormatError( 34238e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 34248e6c099aSJason M. Bills "CollectDiagnosticData"); 34258e6c099aSJason M. Bills return; 34268e6c099aSJason M. Bills } 34278e6c099aSJason M. Bills 3428c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3429c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3430c5a4c82aSJason M. Bills 3431c5a4c82aSJason M. Bills std::string iface; 3432c5a4c82aSJason M. Bills std::string method; 3433c5a4c82aSJason M. Bills std::string taskMatchStr; 3434c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3435c5a4c82aSJason M. Bills { 3436c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3437c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3438c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3439c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3440c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3441c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3442c5a4c82aSJason M. Bills } 3443c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3444c5a4c82aSJason M. Bills { 3445c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3446c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3447c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3448c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3449c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3450c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3451c5a4c82aSJason M. Bills } 3452c5a4c82aSJason M. Bills else 3453c5a4c82aSJason M. Bills { 3454c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3455c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3456c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3457002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3458002d39b4SEd Tanous "CollectDiagnosticData"); 3459c5a4c82aSJason M. Bills return; 3460c5a4c82aSJason M. Bills } 3461c5a4c82aSJason M. Bills 3462c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3463c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 34645e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 346598be3e39SEd Tanous const std::string&) mutable { 34661da66f75SEd Tanous if (ec) 34671da66f75SEd Tanous { 3468002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 34691da66f75SEd Tanous { 3470f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 34711da66f75SEd Tanous } 34724363d3b2SJason M. Bills else if (ec.value() == 34734363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 34744363d3b2SJason M. Bills { 3475002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3476002d39b4SEd Tanous "60"); 34774363d3b2SJason M. Bills } 34781da66f75SEd Tanous else 34791da66f75SEd Tanous { 3480f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34811da66f75SEd Tanous } 34821da66f75SEd Tanous return; 34831da66f75SEd Tanous } 3484002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 34855e7e2dc5SEd Tanous [](const boost::system::error_code& err, sdbusplus::message_t&, 3486002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 348766afe4faSJames Feist if (!err) 348866afe4faSJames Feist { 3489002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3490e5d5006bSJames Feist std::to_string(taskData->index))); 3491831d6b09SJames Feist taskData->state = "Completed"; 349266afe4faSJames Feist } 349332898ceaSJames Feist return task::completed; 349466afe4faSJames Feist }, 3495c5a4c82aSJason M. Bills taskMatchStr); 3496c5a4c82aSJason M. Bills 349746229577SJames Feist task->startTimer(std::chrono::minutes(5)); 349846229577SJames Feist task->populateResp(asyncResp->res); 349998be3e39SEd Tanous task->payload.emplace(std::move(payload)); 35001da66f75SEd Tanous }; 35018e6c099aSJason M. Bills 35021da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3503002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3504002d39b4SEd Tanous iface, method); 35057e860f15SJohn Edward Broadbent }); 35066eda7685SKenny L. Ku } 35076eda7685SKenny L. Ku 3508cb92c03bSAndrew Geissler /** 3509cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3510cb92c03bSAndrew Geissler */ 35117e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3512cb92c03bSAndrew Geissler { 3513cb92c03bSAndrew Geissler /** 3514cb92c03bSAndrew Geissler * Function handles POST method request. 3515cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3516cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3517cb92c03bSAndrew Geissler */ 35187e860f15SJohn Edward Broadbent 35190fda0f12SGeorge Liu BMCWEB_ROUTE( 35200fda0f12SGeorge Liu app, 352122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3522ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 35237e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 352445ca1b86SEd Tanous [&app](const crow::Request& req, 352522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352622d268cbSEd Tanous const std::string& systemName) { 35273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 352845ca1b86SEd Tanous { 352945ca1b86SEd Tanous return; 353045ca1b86SEd Tanous } 353122d268cbSEd Tanous if (systemName != "system") 353222d268cbSEd Tanous { 353322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 353422d268cbSEd Tanous systemName); 353522d268cbSEd Tanous return; 353622d268cbSEd Tanous } 3537cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3538cb92c03bSAndrew Geissler 3539cb92c03bSAndrew Geissler // Process response from Logging service. 35405e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 3541002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3542cb92c03bSAndrew Geissler if (ec) 3543cb92c03bSAndrew Geissler { 3544cb92c03bSAndrew Geissler // TODO Handle for specific error code 3545002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3546cb92c03bSAndrew Geissler asyncResp->res.result( 3547cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3548cb92c03bSAndrew Geissler return; 3549cb92c03bSAndrew Geissler } 3550cb92c03bSAndrew Geissler 3551002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3552cb92c03bSAndrew Geissler }; 3553cb92c03bSAndrew Geissler 3554cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3555cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 35562c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3557cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3558cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35597e860f15SJohn Edward Broadbent }); 3560cb92c03bSAndrew Geissler } 3561a3316fc6SZhikuiRen 3562a3316fc6SZhikuiRen /**************************************************** 3563a3316fc6SZhikuiRen * Redfish PostCode interfaces 3564a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3565a3316fc6SZhikuiRen ******************************************************/ 35667e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3567a3316fc6SZhikuiRen { 356822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3569ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3570002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3571002d39b4SEd Tanous [&app](const crow::Request& req, 357222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 357322d268cbSEd Tanous const std::string& systemName) { 35743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 357545ca1b86SEd Tanous { 357645ca1b86SEd Tanous return; 357745ca1b86SEd Tanous } 357822d268cbSEd Tanous if (systemName != "system") 357922d268cbSEd Tanous { 358022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 358122d268cbSEd Tanous systemName); 358222d268cbSEd Tanous return; 358322d268cbSEd Tanous } 35841476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 35851476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 35861476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 35871476687dSEd Tanous "#LogService.v1_1_0.LogService"; 35881476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35891476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3590ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 35911476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35921476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35931476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35947c8c4058STejas Patil 35957c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35962b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35970fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35987c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35997c8c4058STejas Patil redfishDateTimeOffset.second; 36007c8c4058STejas Patil 3601a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 36027e860f15SJohn Edward Broadbent {"target", 36030fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 36047e860f15SJohn Edward Broadbent }); 3605a3316fc6SZhikuiRen } 3606a3316fc6SZhikuiRen 36077e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3608a3316fc6SZhikuiRen { 36090fda0f12SGeorge Liu BMCWEB_ROUTE( 36100fda0f12SGeorge Liu app, 361122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3612ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3613ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3614432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 36157e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 361645ca1b86SEd Tanous [&app](const crow::Request& req, 361722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 361822d268cbSEd Tanous const std::string& systemName) { 36193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 362045ca1b86SEd Tanous { 362145ca1b86SEd Tanous return; 362245ca1b86SEd Tanous } 362322d268cbSEd Tanous if (systemName != "system") 362422d268cbSEd Tanous { 362522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 362622d268cbSEd Tanous systemName); 362722d268cbSEd Tanous return; 362822d268cbSEd Tanous } 3629a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3630a3316fc6SZhikuiRen 3631a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3632a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 36335e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3634a3316fc6SZhikuiRen if (ec) 3635a3316fc6SZhikuiRen { 3636a3316fc6SZhikuiRen // TODO Handle for specific error code 3637002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 36387e860f15SJohn Edward Broadbent << ec; 3639002d39b4SEd Tanous asyncResp->res.result( 3640002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3641a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3642a3316fc6SZhikuiRen return; 3643a3316fc6SZhikuiRen } 3644a3316fc6SZhikuiRen }, 364515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 364615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3647a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 36487e860f15SJohn Edward Broadbent }); 3649a3316fc6SZhikuiRen } 3650a3316fc6SZhikuiRen 36516f284d24SJiaqing Zhao /** 36526f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 36536f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 36546f284d24SJiaqing Zhao * 36556f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 36566f284d24SJiaqing Zhao * @param[out] currentValue Current value 36576f284d24SJiaqing Zhao * @param[out] index Index value 36586f284d24SJiaqing Zhao * 36596f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 36606f284d24SJiaqing Zhao */ 36616f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 36626f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 36636f284d24SJiaqing Zhao { 36646f284d24SJiaqing Zhao std::vector<std::string> split; 366550ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 36666f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 36676f284d24SJiaqing Zhao { 36686f284d24SJiaqing Zhao return false; 36696f284d24SJiaqing Zhao } 36706f284d24SJiaqing Zhao 36716f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36726f284d24SJiaqing Zhao const char* start = split[0].data() + 1; 36736f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36746f284d24SJiaqing Zhao const char* end = split[0].data() + split[0].size(); 36756f284d24SJiaqing Zhao auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 36766f284d24SJiaqing Zhao 36776f284d24SJiaqing Zhao if (ptrIndex != end || ecIndex != std::errc()) 36786f284d24SJiaqing Zhao { 36796f284d24SJiaqing Zhao return false; 36806f284d24SJiaqing Zhao } 36816f284d24SJiaqing Zhao 36826f284d24SJiaqing Zhao start = split[1].data(); 36836f284d24SJiaqing Zhao 36846f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36856f284d24SJiaqing Zhao end = split[1].data() + split[1].size(); 36866f284d24SJiaqing Zhao auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 36876f284d24SJiaqing Zhao 36886f284d24SJiaqing Zhao return ptrValue == end && ecValue == std::errc(); 36896f284d24SJiaqing Zhao } 36906f284d24SJiaqing Zhao 36916f284d24SJiaqing Zhao static bool fillPostCodeEntry( 36928d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 36936c9a279eSManojkiran Eda const boost::container::flat_map< 36946c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3695a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3696a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3697a3316fc6SZhikuiRen { 3698a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3699fffb8c1fSEd Tanous const registries::Message* message = 3700fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3701a3316fc6SZhikuiRen 3702a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3703a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 37046c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37056c9a279eSManojkiran Eda code : postcode) 3706a3316fc6SZhikuiRen { 3707a3316fc6SZhikuiRen currentCodeIndex++; 3708a3316fc6SZhikuiRen std::string postcodeEntryID = 3709a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3710a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3711a3316fc6SZhikuiRen 3712a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3713a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3714a3316fc6SZhikuiRen 3715a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3716a3316fc6SZhikuiRen { // already incremented 3717a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3718a3316fc6SZhikuiRen } 3719a3316fc6SZhikuiRen else 3720a3316fc6SZhikuiRen { 3721a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3722a3316fc6SZhikuiRen } 3723a3316fc6SZhikuiRen 3724a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3725a3316fc6SZhikuiRen // not fall between top and skip 3726a3316fc6SZhikuiRen if ((codeIndex == 0) && 3727a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3728a3316fc6SZhikuiRen { 3729a3316fc6SZhikuiRen continue; 3730a3316fc6SZhikuiRen } 3731a3316fc6SZhikuiRen 37324e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3733a3316fc6SZhikuiRen // currentIndex 3734a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3735a3316fc6SZhikuiRen { 3736a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3737a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3738a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3739a3316fc6SZhikuiRen continue; 3740a3316fc6SZhikuiRen } 3741a3316fc6SZhikuiRen 3742a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3743a3316fc6SZhikuiRen // index 3744a3316fc6SZhikuiRen 3745a3316fc6SZhikuiRen // Get the Created time from the timestamp 3746a3316fc6SZhikuiRen std::string entryTimeStr; 37472a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 3748a3316fc6SZhikuiRen 3749a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3750a3316fc6SZhikuiRen std::ostringstream hexCode; 3751a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 37526c9a279eSManojkiran Eda << std::get<0>(code.second); 3753a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3754a3316fc6SZhikuiRen // Set Fixed -Point Notation 3755a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3756a3316fc6SZhikuiRen // Set precision to 4 digits 3757a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3758a3316fc6SZhikuiRen // Add double to stream 3759a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3760a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3761a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3762a3316fc6SZhikuiRen 3763a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3764a3316fc6SZhikuiRen std::string msg; 3765a3316fc6SZhikuiRen if (message != nullptr) 3766a3316fc6SZhikuiRen { 3767a3316fc6SZhikuiRen msg = message->message; 3768a3316fc6SZhikuiRen 3769a3316fc6SZhikuiRen // fill in this post code value 3770a3316fc6SZhikuiRen int i = 0; 3771a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3772a3316fc6SZhikuiRen { 3773a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3774a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3775a3316fc6SZhikuiRen if (argPos != std::string::npos) 3776a3316fc6SZhikuiRen { 3777a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3778a3316fc6SZhikuiRen } 3779a3316fc6SZhikuiRen } 3780a3316fc6SZhikuiRen } 3781a3316fc6SZhikuiRen 3782d4342a92STim Lee // Get Severity template from message registry 3783d4342a92STim Lee std::string severity; 3784d4342a92STim Lee if (message != nullptr) 3785d4342a92STim Lee { 37865f2b84eeSEd Tanous severity = message->messageSeverity; 3787d4342a92STim Lee } 3788d4342a92STim Lee 37896f284d24SJiaqing Zhao // Format entry 37906f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37919c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3792eddfc437SWilly Tu bmcLogEntry["@odata.id"] = crow::utility::urlFromPieces( 3793eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "LogServices", "PostCodes", 3794eddfc437SWilly Tu "Entries", postcodeEntryID); 379584afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 379684afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 379784afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 379884afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 379984afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 380084afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 380184afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 380284afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3803647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3804647b3cdcSGeorge Liu { 3805647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3806647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3807647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3808647b3cdcSGeorge Liu } 38096f284d24SJiaqing Zhao 38106f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 38116f284d24SJiaqing Zhao // that entry in this case 38126f284d24SJiaqing Zhao if (codeIndex != 0) 38136f284d24SJiaqing Zhao { 38146f284d24SJiaqing Zhao aResp->res.jsonValue.update(bmcLogEntry); 38156f284d24SJiaqing Zhao return true; 3816a3316fc6SZhikuiRen } 38176f284d24SJiaqing Zhao 38186f284d24SJiaqing Zhao nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 38196f284d24SJiaqing Zhao logEntryArray.push_back(std::move(bmcLogEntry)); 38206f284d24SJiaqing Zhao } 38216f284d24SJiaqing Zhao 38226f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 38236f284d24SJiaqing Zhao return false; 3824a3316fc6SZhikuiRen } 3825a3316fc6SZhikuiRen 38268d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 38276f284d24SJiaqing Zhao const std::string& entryId) 3828a3316fc6SZhikuiRen { 38296f284d24SJiaqing Zhao uint16_t bootIndex = 0; 38306f284d24SJiaqing Zhao uint64_t codeIndex = 0; 38316f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 38326f284d24SJiaqing Zhao { 38336f284d24SJiaqing Zhao // Requested ID was not found 38346f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 38356f284d24SJiaqing Zhao return; 38366f284d24SJiaqing Zhao } 38376f284d24SJiaqing Zhao 38386f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 38396f284d24SJiaqing Zhao { 38406f284d24SJiaqing Zhao // 0 is an invalid index 38416f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 38426f284d24SJiaqing Zhao return; 38436f284d24SJiaqing Zhao } 38446f284d24SJiaqing Zhao 3845a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 38466f284d24SJiaqing Zhao [aResp, entryId, bootIndex, 38475e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 38486c9a279eSManojkiran Eda const boost::container::flat_map< 38496c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38506c9a279eSManojkiran Eda postcode) { 3851a3316fc6SZhikuiRen if (ec) 3852a3316fc6SZhikuiRen { 3853a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3854a3316fc6SZhikuiRen messages::internalError(aResp->res); 3855a3316fc6SZhikuiRen return; 3856a3316fc6SZhikuiRen } 3857a3316fc6SZhikuiRen 3858a3316fc6SZhikuiRen if (postcode.empty()) 3859a3316fc6SZhikuiRen { 38606f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 3861a3316fc6SZhikuiRen return; 3862a3316fc6SZhikuiRen } 3863a3316fc6SZhikuiRen 38646f284d24SJiaqing Zhao if (!fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex)) 38656f284d24SJiaqing Zhao { 38666f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 38676f284d24SJiaqing Zhao return; 38686f284d24SJiaqing Zhao } 3869a3316fc6SZhikuiRen }, 387015124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 387115124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3872a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3873a3316fc6SZhikuiRen bootIndex); 3874a3316fc6SZhikuiRen } 3875a3316fc6SZhikuiRen 38768d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3877a3316fc6SZhikuiRen const uint16_t bootIndex, 3878a3316fc6SZhikuiRen const uint16_t bootCount, 38793648c8beSEd Tanous const uint64_t entryCount, size_t skip, 38803648c8beSEd Tanous size_t top) 3881a3316fc6SZhikuiRen { 3882a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3883a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 38845e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 38856c9a279eSManojkiran Eda const boost::container::flat_map< 38866c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38876c9a279eSManojkiran Eda postcode) { 3888a3316fc6SZhikuiRen if (ec) 3889a3316fc6SZhikuiRen { 3890a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3891a3316fc6SZhikuiRen messages::internalError(aResp->res); 3892a3316fc6SZhikuiRen return; 3893a3316fc6SZhikuiRen } 3894a3316fc6SZhikuiRen 3895a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3896a3316fc6SZhikuiRen if (!postcode.empty()) 3897a3316fc6SZhikuiRen { 3898a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38993648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3900a3316fc6SZhikuiRen { 39013648c8beSEd Tanous uint64_t thisBootSkip = 39023648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 39033648c8beSEd Tanous entryCount; 3904a3316fc6SZhikuiRen uint64_t thisBootTop = 39053648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 39063648c8beSEd Tanous entryCount; 3907a3316fc6SZhikuiRen 3908002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3909002d39b4SEd Tanous thisBootTop); 3910a3316fc6SZhikuiRen } 3911a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3912a3316fc6SZhikuiRen } 3913a3316fc6SZhikuiRen 3914a3316fc6SZhikuiRen // continue to previous bootIndex 3915a3316fc6SZhikuiRen if (bootIndex < bootCount) 3916a3316fc6SZhikuiRen { 3917a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3918a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3919a3316fc6SZhikuiRen } 392081584abeSJiaqing Zhao else if (skip + top < endCount) 3921a3316fc6SZhikuiRen { 3922a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 39230fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3924a3316fc6SZhikuiRen std::to_string(skip + top); 3925a3316fc6SZhikuiRen } 3926a3316fc6SZhikuiRen }, 392715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 392815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3929a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3930a3316fc6SZhikuiRen bootIndex); 3931a3316fc6SZhikuiRen } 3932a3316fc6SZhikuiRen 39338d1b46d7Szhanghch05 static void 39348d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 39353648c8beSEd Tanous size_t skip, size_t top) 3936a3316fc6SZhikuiRen { 3937a3316fc6SZhikuiRen uint64_t entryCount = 0; 39381e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 39391e1e598dSJonathan Doman *crow::connections::systemBus, 39401e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 39411e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 39421e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 39435e7e2dc5SEd Tanous [aResp, entryCount, skip, top](const boost::system::error_code& ec, 39441e1e598dSJonathan Doman const uint16_t bootCount) { 3945a3316fc6SZhikuiRen if (ec) 3946a3316fc6SZhikuiRen { 3947a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3948a3316fc6SZhikuiRen messages::internalError(aResp->res); 3949a3316fc6SZhikuiRen return; 3950a3316fc6SZhikuiRen } 39511e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 39521e1e598dSJonathan Doman }); 3953a3316fc6SZhikuiRen } 3954a3316fc6SZhikuiRen 39557e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3956a3316fc6SZhikuiRen { 39577e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 395822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3959ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 39607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 396145ca1b86SEd Tanous [&app](const crow::Request& req, 396222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 396322d268cbSEd Tanous const std::string& systemName) { 3964c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3965c937d2bfSEd Tanous .canDelegateTop = true, 3966c937d2bfSEd Tanous .canDelegateSkip = true, 3967c937d2bfSEd Tanous }; 3968c937d2bfSEd Tanous query_param::Query delegatedQuery; 3969c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39703ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 397145ca1b86SEd Tanous { 397245ca1b86SEd Tanous return; 397345ca1b86SEd Tanous } 397422d268cbSEd Tanous 397522d268cbSEd Tanous if (systemName != "system") 397622d268cbSEd Tanous { 397722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 397822d268cbSEd Tanous systemName); 397922d268cbSEd Tanous return; 398022d268cbSEd Tanous } 3981a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3982a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3983a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3984a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3985a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3986a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3987a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3988a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3989a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39903648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39915143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39923648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39937e860f15SJohn Edward Broadbent }); 3994a3316fc6SZhikuiRen } 3995a3316fc6SZhikuiRen 3996647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3997647b3cdcSGeorge Liu { 39980fda0f12SGeorge Liu BMCWEB_ROUTE( 39990fda0f12SGeorge Liu app, 400022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4001647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4002647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 400345ca1b86SEd Tanous [&app](const crow::Request& req, 4004647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 400522d268cbSEd Tanous const std::string& systemName, 4006647b3cdcSGeorge Liu const std::string& postCodeID) { 40073ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 400845ca1b86SEd Tanous { 400945ca1b86SEd Tanous return; 401045ca1b86SEd Tanous } 401199351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 401299351cd8SEd Tanous req.getHeaderValue("Accept"), 40134a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4014647b3cdcSGeorge Liu { 4015002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4016647b3cdcSGeorge Liu return; 4017647b3cdcSGeorge Liu } 401822d268cbSEd Tanous if (systemName != "system") 401922d268cbSEd Tanous { 402022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 402122d268cbSEd Tanous systemName); 402222d268cbSEd Tanous return; 402322d268cbSEd Tanous } 4024647b3cdcSGeorge Liu 4025647b3cdcSGeorge Liu uint64_t currentValue = 0; 4026647b3cdcSGeorge Liu uint16_t index = 0; 4027647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4028647b3cdcSGeorge Liu { 4029002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4030647b3cdcSGeorge Liu return; 4031647b3cdcSGeorge Liu } 4032647b3cdcSGeorge Liu 4033647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4034647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 40355e7e2dc5SEd Tanous const boost::system::error_code& ec, 4036002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4037002d39b4SEd Tanous postcodes) { 4038647b3cdcSGeorge Liu if (ec.value() == EBADR) 4039647b3cdcSGeorge Liu { 4040002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4041002d39b4SEd Tanous postCodeID); 4042647b3cdcSGeorge Liu return; 4043647b3cdcSGeorge Liu } 4044647b3cdcSGeorge Liu if (ec) 4045647b3cdcSGeorge Liu { 4046647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 4047647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4048647b3cdcSGeorge Liu return; 4049647b3cdcSGeorge Liu } 4050647b3cdcSGeorge Liu 4051647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4052002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4053647b3cdcSGeorge Liu { 4054a7405d5fSGunnar Mills BMCWEB_LOG_WARNING << "Wrong currentValue value"; 4055002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4056002d39b4SEd Tanous postCodeID); 4057647b3cdcSGeorge Liu return; 4058647b3cdcSGeorge Liu } 4059647b3cdcSGeorge Liu 40609eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 406146ff87baSEd Tanous if (c.empty()) 4062647b3cdcSGeorge Liu { 4063a7405d5fSGunnar Mills BMCWEB_LOG_WARNING << "No found post code data"; 4064002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4065002d39b4SEd Tanous postCodeID); 4066647b3cdcSGeorge Liu return; 4067647b3cdcSGeorge Liu } 406846ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 406946ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 407046ff87baSEd Tanous std::string_view strData(d, c.size()); 4071647b3cdcSGeorge Liu 4072d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4073647b3cdcSGeorge Liu "application/octet-stream"); 4074d9f6c621SEd Tanous asyncResp->res.addHeader( 4075d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4076002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4077647b3cdcSGeorge Liu }, 4078647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4079647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4080002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4081647b3cdcSGeorge Liu }); 4082647b3cdcSGeorge Liu } 4083647b3cdcSGeorge Liu 40847e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4085a3316fc6SZhikuiRen { 40867e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 408722d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4088ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40897e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 409045ca1b86SEd Tanous [&app](const crow::Request& req, 40917e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 409222d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 409445ca1b86SEd Tanous { 409545ca1b86SEd Tanous return; 409645ca1b86SEd Tanous } 409722d268cbSEd Tanous if (systemName != "system") 409822d268cbSEd Tanous { 409922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 410022d268cbSEd Tanous systemName); 410122d268cbSEd Tanous return; 410222d268cbSEd Tanous } 410322d268cbSEd Tanous 41046f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 41057e860f15SJohn Edward Broadbent }); 4106a3316fc6SZhikuiRen } 4107a3316fc6SZhikuiRen 41081da66f75SEd Tanous } // namespace redfish 4109