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 18b7028ebfSSpencer Ku #include "gzfile.hpp" 19647b3cdcSGeorge Liu #include "http_utility.hpp" 20b7028ebfSSpencer Ku #include "human_sort.hpp" 214851d45dSJason M. Bills #include "registries.hpp" 224851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 234851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 2446229577SJames Feist #include "task.hpp" 251da66f75SEd Tanous 26e1f26343SJason M. Bills #include <systemd/sd-journal.h> 278e31778eSAsmitha Karunanithi #include <tinyxml2.h> 28400fd1fbSAdriana Kobylak #include <unistd.h> 29e1f26343SJason M. Bills 307e860f15SJohn Edward Broadbent #include <app.hpp> 319896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 3211ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 33400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 344851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 3507c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 361da66f75SEd Tanous #include <boost/container/flat_map.hpp> 371ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 38168e20c1SEd Tanous #include <dbus_utility.hpp> 39cb92c03bSAndrew Geissler #include <error_messages.hpp> 4045ca1b86SEd Tanous #include <query.hpp> 41ed398213SEd Tanous #include <registries/privilege_registry.hpp> 42d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 43d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 44d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp> 452b82937eSEd Tanous #include <utils/time_utils.hpp> 461214b7e7SGunnar Mills 47647b3cdcSGeorge Liu #include <charconv> 484418c7f0SJames Feist #include <filesystem> 4975710de2SXiaochao Ma #include <optional> 5026702d01SEd Tanous #include <span> 51cd225da8SJason M. Bills #include <string_view> 52abf2add6SEd Tanous #include <variant> 531da66f75SEd Tanous 541da66f75SEd Tanous namespace redfish 551da66f75SEd Tanous { 561da66f75SEd Tanous 575b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump"; 585b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump"; 595b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump"; 605b61b5e8SJason M. Bills constexpr char const* deleteAllInterface = 615b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 625b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface = 63424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 646eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface = 656eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 661da66f75SEd Tanous 678e31778eSAsmitha Karunanithi enum class DumpCreationProgress 688e31778eSAsmitha Karunanithi { 698e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 708e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 718e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 728e31778eSAsmitha Karunanithi }; 738e31778eSAsmitha Karunanithi 74fffb8c1fSEd Tanous namespace registries 754851d45dSJason M. Bills { 7626702d01SEd Tanous static const Message* 7726702d01SEd Tanous getMessageFromRegistry(const std::string& messageKey, 7826702d01SEd Tanous const std::span<const MessageEntry> registry) 794851d45dSJason M. Bills { 80002d39b4SEd Tanous std::span<const MessageEntry>::iterator messageIt = 81002d39b4SEd Tanous std::find_if(registry.begin(), registry.end(), 824851d45dSJason M. Bills [&messageKey](const MessageEntry& messageEntry) { 83e662eae8SEd Tanous return std::strcmp(messageEntry.first, messageKey.c_str()) == 0; 844851d45dSJason M. Bills }); 8526702d01SEd Tanous if (messageIt != registry.end()) 864851d45dSJason M. Bills { 874851d45dSJason M. Bills return &messageIt->second; 884851d45dSJason M. Bills } 894851d45dSJason M. Bills 904851d45dSJason M. Bills return nullptr; 914851d45dSJason M. Bills } 924851d45dSJason M. Bills 934851d45dSJason M. Bills static const Message* getMessage(const std::string_view& messageID) 944851d45dSJason M. Bills { 954851d45dSJason M. Bills // Redfish MessageIds are in the form 964851d45dSJason M. Bills // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find 974851d45dSJason M. Bills // the right Message 984851d45dSJason M. Bills std::vector<std::string> fields; 994851d45dSJason M. Bills fields.reserve(4); 1004851d45dSJason M. Bills boost::split(fields, messageID, boost::is_any_of(".")); 10102cad96eSEd Tanous const std::string& registryName = fields[0]; 10202cad96eSEd Tanous const std::string& messageKey = fields[3]; 1034851d45dSJason M. Bills 1044851d45dSJason M. Bills // Find the right registry and check it for the MessageKey 1054851d45dSJason M. Bills if (std::string(base::header.registryPrefix) == registryName) 1064851d45dSJason M. Bills { 1074851d45dSJason M. Bills return getMessageFromRegistry( 10826702d01SEd Tanous messageKey, std::span<const MessageEntry>(base::registry)); 1094851d45dSJason M. Bills } 1104851d45dSJason M. Bills if (std::string(openbmc::header.registryPrefix) == registryName) 1114851d45dSJason M. Bills { 1124851d45dSJason M. Bills return getMessageFromRegistry( 11326702d01SEd Tanous messageKey, std::span<const MessageEntry>(openbmc::registry)); 1144851d45dSJason M. Bills } 1154851d45dSJason M. Bills return nullptr; 1164851d45dSJason M. Bills } 117fffb8c1fSEd Tanous } // namespace registries 1184851d45dSJason M. Bills 119f6150403SJames Feist namespace fs = std::filesystem; 1201da66f75SEd Tanous 121cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 122cb92c03bSAndrew Geissler { 123d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 124d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 125d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 126d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 127cb92c03bSAndrew Geissler { 128cb92c03bSAndrew Geissler return "Critical"; 129cb92c03bSAndrew Geissler } 1303174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 131d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 132d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 133cb92c03bSAndrew Geissler { 134cb92c03bSAndrew Geissler return "OK"; 135cb92c03bSAndrew Geissler } 1363174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 137cb92c03bSAndrew Geissler { 138cb92c03bSAndrew Geissler return "Warning"; 139cb92c03bSAndrew Geissler } 140cb92c03bSAndrew Geissler return ""; 141cb92c03bSAndrew Geissler } 142cb92c03bSAndrew Geissler 1437e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 14439e77504SEd Tanous const std::string_view& field, 14539e77504SEd Tanous std::string_view& contents) 14616428a1aSJason M. Bills { 14716428a1aSJason M. Bills const char* data = nullptr; 14816428a1aSJason M. Bills size_t length = 0; 14916428a1aSJason M. Bills int ret = 0; 15016428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 15146ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 15246ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 15346ff87baSEd Tanous 15446ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 15516428a1aSJason M. Bills if (ret < 0) 15616428a1aSJason M. Bills { 15716428a1aSJason M. Bills return ret; 15816428a1aSJason M. Bills } 15939e77504SEd Tanous contents = std::string_view(data, length); 16016428a1aSJason M. Bills // Only use the content after the "=" character. 16181ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 16216428a1aSJason M. Bills return ret; 16316428a1aSJason M. Bills } 16416428a1aSJason M. Bills 1657e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 1667e860f15SJohn Edward Broadbent const std::string_view& field, 1677e860f15SJohn Edward Broadbent const int& base, long int& contents) 16816428a1aSJason M. Bills { 16916428a1aSJason M. Bills int ret = 0; 17039e77504SEd Tanous std::string_view metadata; 17116428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 17216428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 17316428a1aSJason M. Bills if (ret < 0) 17416428a1aSJason M. Bills { 17516428a1aSJason M. Bills return ret; 17616428a1aSJason M. Bills } 177b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 17816428a1aSJason M. Bills return ret; 17916428a1aSJason M. Bills } 18016428a1aSJason M. Bills 1817e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1827e860f15SJohn Edward Broadbent std::string& entryTimestamp) 183a3316fc6SZhikuiRen { 184a3316fc6SZhikuiRen int ret = 0; 185a3316fc6SZhikuiRen uint64_t timestamp = 0; 186a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 187a3316fc6SZhikuiRen if (ret < 0) 188a3316fc6SZhikuiRen { 189a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 190a3316fc6SZhikuiRen << strerror(-ret); 191a3316fc6SZhikuiRen return false; 192a3316fc6SZhikuiRen } 1932b82937eSEd Tanous entryTimestamp = 1942b82937eSEd Tanous redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000); 1959c620e21SAsmitha Karunanithi return true; 196a3316fc6SZhikuiRen } 19750b8a43aSEd Tanous 1987e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 199e85d6b16SJason M. Bills const bool firstEntry = true) 20016428a1aSJason M. Bills { 20116428a1aSJason M. Bills int ret = 0; 20216428a1aSJason M. Bills static uint64_t prevTs = 0; 20316428a1aSJason M. Bills static int index = 0; 204e85d6b16SJason M. Bills if (firstEntry) 205e85d6b16SJason M. Bills { 206e85d6b16SJason M. Bills prevTs = 0; 207e85d6b16SJason M. Bills } 208e85d6b16SJason M. Bills 20916428a1aSJason M. Bills // Get the entry timestamp 21016428a1aSJason M. Bills uint64_t curTs = 0; 21116428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 21216428a1aSJason M. Bills if (ret < 0) 21316428a1aSJason M. Bills { 21416428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 21516428a1aSJason M. Bills << strerror(-ret); 21616428a1aSJason M. Bills return false; 21716428a1aSJason M. Bills } 21816428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 21916428a1aSJason M. Bills if (curTs == prevTs) 22016428a1aSJason M. Bills { 22116428a1aSJason M. Bills index++; 22216428a1aSJason M. Bills } 22316428a1aSJason M. Bills else 22416428a1aSJason M. Bills { 22516428a1aSJason M. Bills // Otherwise, reset it 22616428a1aSJason M. Bills index = 0; 22716428a1aSJason M. Bills } 22816428a1aSJason M. Bills // Save the timestamp 22916428a1aSJason M. Bills prevTs = curTs; 23016428a1aSJason M. Bills 23116428a1aSJason M. Bills entryID = std::to_string(curTs); 23216428a1aSJason M. Bills if (index > 0) 23316428a1aSJason M. Bills { 23416428a1aSJason M. Bills entryID += "_" + std::to_string(index); 23516428a1aSJason M. Bills } 23616428a1aSJason M. Bills return true; 23716428a1aSJason M. Bills } 23816428a1aSJason M. Bills 239e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 240e85d6b16SJason M. Bills const bool firstEntry = true) 24195820184SJason M. Bills { 242271584abSEd Tanous static time_t prevTs = 0; 24395820184SJason M. Bills static int index = 0; 244e85d6b16SJason M. Bills if (firstEntry) 245e85d6b16SJason M. Bills { 246e85d6b16SJason M. Bills prevTs = 0; 247e85d6b16SJason M. Bills } 248e85d6b16SJason M. Bills 24995820184SJason M. Bills // Get the entry timestamp 250271584abSEd Tanous std::time_t curTs = 0; 25195820184SJason M. Bills std::tm timeStruct = {}; 25295820184SJason M. Bills std::istringstream entryStream(logEntry); 25395820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 25495820184SJason M. Bills { 25595820184SJason M. Bills curTs = std::mktime(&timeStruct); 25695820184SJason M. Bills } 25795820184SJason M. Bills // If the timestamp isn't unique, increment the index 25895820184SJason M. Bills if (curTs == prevTs) 25995820184SJason M. Bills { 26095820184SJason M. Bills index++; 26195820184SJason M. Bills } 26295820184SJason M. Bills else 26395820184SJason M. Bills { 26495820184SJason M. Bills // Otherwise, reset it 26595820184SJason M. Bills index = 0; 26695820184SJason M. Bills } 26795820184SJason M. Bills // Save the timestamp 26895820184SJason M. Bills prevTs = curTs; 26995820184SJason M. Bills 27095820184SJason M. Bills entryID = std::to_string(curTs); 27195820184SJason M. Bills if (index > 0) 27295820184SJason M. Bills { 27395820184SJason M. Bills entryID += "_" + std::to_string(index); 27495820184SJason M. Bills } 27595820184SJason M. Bills return true; 27695820184SJason M. Bills } 27795820184SJason M. Bills 2787e860f15SJohn Edward Broadbent inline static bool 2798d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2808d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2818d1b46d7Szhanghch05 uint64_t& index) 28216428a1aSJason M. Bills { 28316428a1aSJason M. Bills if (entryID.empty()) 28416428a1aSJason M. Bills { 28516428a1aSJason M. Bills return false; 28616428a1aSJason M. Bills } 28716428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 28839e77504SEd Tanous std::string_view tsStr(entryID); 28916428a1aSJason M. Bills 29081ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 29171d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 29216428a1aSJason M. Bills { 29316428a1aSJason M. Bills // Timestamp has an index 29416428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 29539e77504SEd Tanous std::string_view indexStr(entryID); 29616428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 297c0bd5e4bSEd Tanous auto [ptr, ec] = std::from_chars( 298c0bd5e4bSEd Tanous indexStr.data(), indexStr.data() + indexStr.size(), index); 299c0bd5e4bSEd Tanous if (ec != std::errc()) 30016428a1aSJason M. Bills { 3019db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 30216428a1aSJason M. Bills return false; 30316428a1aSJason M. Bills } 30416428a1aSJason M. Bills } 30516428a1aSJason M. Bills // Timestamp has no index 306c0bd5e4bSEd Tanous auto [ptr, ec] = 307c0bd5e4bSEd Tanous std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp); 308c0bd5e4bSEd Tanous if (ec != std::errc()) 30916428a1aSJason M. Bills { 3109db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 31116428a1aSJason M. Bills return false; 31216428a1aSJason M. Bills } 31316428a1aSJason M. Bills return true; 31416428a1aSJason M. Bills } 31516428a1aSJason M. Bills 31695820184SJason M. Bills static bool 31795820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 31895820184SJason M. Bills { 31995820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 32095820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 32195820184SJason M. Bills 32295820184SJason M. Bills // Loop through the directory looking for redfish log files 32395820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 32495820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 32595820184SJason M. Bills { 32695820184SJason M. Bills // If we find a redfish log file, save the path 32795820184SJason M. Bills std::string filename = dirEnt.path().filename(); 32811ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 32995820184SJason M. Bills { 33095820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 33195820184SJason M. Bills } 33295820184SJason M. Bills } 33395820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 33495820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 33595820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 33695820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 33795820184SJason M. Bills 33895820184SJason M. Bills return !redfishLogFiles.empty(); 33995820184SJason M. Bills } 34095820184SJason M. Bills 341aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3422d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 343c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 344aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 345aefe3786SClaire Weinan { 346aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 347aefe3786SClaire Weinan { 348aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 349aefe3786SClaire Weinan { 350aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 351aefe3786SClaire Weinan { 352aefe3786SClaire Weinan if (propertyMap.first == "Status") 353aefe3786SClaire Weinan { 354aefe3786SClaire Weinan const auto* status = 355aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 356aefe3786SClaire Weinan if (status == nullptr) 357aefe3786SClaire Weinan { 358aefe3786SClaire Weinan messages::internalError(asyncResp->res); 359aefe3786SClaire Weinan break; 360aefe3786SClaire Weinan } 361aefe3786SClaire Weinan dumpStatus = *status; 362aefe3786SClaire Weinan } 363aefe3786SClaire Weinan } 364aefe3786SClaire Weinan } 365aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 366aefe3786SClaire Weinan { 367aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 368aefe3786SClaire Weinan { 369aefe3786SClaire Weinan if (propertyMap.first == "Size") 370aefe3786SClaire Weinan { 371aefe3786SClaire Weinan const auto* sizePtr = 372aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 373aefe3786SClaire Weinan if (sizePtr == nullptr) 374aefe3786SClaire Weinan { 375aefe3786SClaire Weinan messages::internalError(asyncResp->res); 376aefe3786SClaire Weinan break; 377aefe3786SClaire Weinan } 378aefe3786SClaire Weinan size = *sizePtr; 379aefe3786SClaire Weinan break; 380aefe3786SClaire Weinan } 381aefe3786SClaire Weinan } 382aefe3786SClaire Weinan } 383aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 386aefe3786SClaire Weinan { 387aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 388aefe3786SClaire Weinan { 389aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 390aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 391aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 392aefe3786SClaire Weinan { 393aefe3786SClaire Weinan messages::internalError(asyncResp->res); 394aefe3786SClaire Weinan break; 395aefe3786SClaire Weinan } 396c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 397aefe3786SClaire Weinan break; 398aefe3786SClaire Weinan } 399aefe3786SClaire Weinan } 400aefe3786SClaire Weinan } 401aefe3786SClaire Weinan } 402aefe3786SClaire Weinan } 403aefe3786SClaire Weinan 40421ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 405fdd26906SClaire Weinan { 406fdd26906SClaire Weinan std::string entriesPath; 407fdd26906SClaire Weinan 408fdd26906SClaire Weinan if (dumpType == "BMC") 409fdd26906SClaire Weinan { 410fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 411fdd26906SClaire Weinan } 412fdd26906SClaire Weinan else if (dumpType == "FaultLog") 413fdd26906SClaire Weinan { 414fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 415fdd26906SClaire Weinan } 416fdd26906SClaire Weinan else if (dumpType == "System") 417fdd26906SClaire Weinan { 418fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 419fdd26906SClaire Weinan } 420fdd26906SClaire Weinan else 421fdd26906SClaire Weinan { 422fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 423fdd26906SClaire Weinan << dumpType; 424fdd26906SClaire Weinan } 425fdd26906SClaire Weinan 426fdd26906SClaire Weinan // Returns empty string on error 427fdd26906SClaire Weinan return entriesPath; 428fdd26906SClaire Weinan } 429fdd26906SClaire Weinan 4308d1b46d7Szhanghch05 inline void 4318d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4325cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4335cb1dd27SAsmitha Karunanithi { 434fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 435fdd26906SClaire Weinan if (entriesPath.empty()) 4365cb1dd27SAsmitha Karunanithi { 4375cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4385cb1dd27SAsmitha Karunanithi return; 4395cb1dd27SAsmitha Karunanithi } 4405cb1dd27SAsmitha Karunanithi 4415cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 442fdd26906SClaire Weinan [asyncResp, entriesPath, 443711ac7a9SEd Tanous dumpType](const boost::system::error_code ec, 444711ac7a9SEd Tanous dbus::utility::ManagedObjectType& resp) { 4455cb1dd27SAsmitha Karunanithi if (ec) 4465cb1dd27SAsmitha Karunanithi { 4475cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4485cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4495cb1dd27SAsmitha Karunanithi return; 4505cb1dd27SAsmitha Karunanithi } 4515cb1dd27SAsmitha Karunanithi 452fdd26906SClaire Weinan // Remove ending slash 453fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 454fdd26906SClaire Weinan if (!odataIdStr.empty()) 455fdd26906SClaire Weinan { 456fdd26906SClaire Weinan odataIdStr.pop_back(); 457fdd26906SClaire Weinan } 458fdd26906SClaire Weinan 459fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 460fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 461fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 462fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 463fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = 464fdd26906SClaire Weinan "Collection of " + dumpType + " Dump Entries"; 465fdd26906SClaire Weinan 4665cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4675cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 468b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 469b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 470002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 4715cb1dd27SAsmitha Karunanithi 472002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 473002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 474002d39b4SEd Tanous r.first.filename()); 475565dfb6fSClaire Weinan }); 476565dfb6fSClaire Weinan 4775cb1dd27SAsmitha Karunanithi for (auto& object : resp) 4785cb1dd27SAsmitha Karunanithi { 479b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 4805cb1dd27SAsmitha Karunanithi { 4815cb1dd27SAsmitha Karunanithi continue; 4825cb1dd27SAsmitha Karunanithi } 483c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4845cb1dd27SAsmitha Karunanithi uint64_t size = 0; 48535440d18SAsmitha Karunanithi std::string dumpStatus; 486433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 4872dfd18efSEd Tanous 4882dfd18efSEd Tanous std::string entryID = object.first.filename(); 4892dfd18efSEd Tanous if (entryID.empty()) 4905cb1dd27SAsmitha Karunanithi { 4915cb1dd27SAsmitha Karunanithi continue; 4925cb1dd27SAsmitha Karunanithi } 4935cb1dd27SAsmitha Karunanithi 494c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 495aefe3786SClaire Weinan asyncResp); 4965cb1dd27SAsmitha Karunanithi 4970fda0f12SGeorge Liu if (dumpStatus != 4980fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 49935440d18SAsmitha Karunanithi !dumpStatus.empty()) 50035440d18SAsmitha Karunanithi { 50135440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 50235440d18SAsmitha Karunanithi continue; 50335440d18SAsmitha Karunanithi } 50435440d18SAsmitha Karunanithi 5059c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 506fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5075cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5085cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5095cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 510*bbd80db8SClaire Weinan thisEntry["Created"] = 511*bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5125cb1dd27SAsmitha Karunanithi 5135cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5145cb1dd27SAsmitha Karunanithi { 515d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 516d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 517fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 518fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5195cb1dd27SAsmitha Karunanithi } 5205cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5215cb1dd27SAsmitha Karunanithi { 522d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 523d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 524d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 525fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 526fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5275cb1dd27SAsmitha Karunanithi } 52835440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5295cb1dd27SAsmitha Karunanithi } 530002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5315cb1dd27SAsmitha Karunanithi }, 5325cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5335cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 5345cb1dd27SAsmitha Karunanithi } 5355cb1dd27SAsmitha Karunanithi 5368d1b46d7Szhanghch05 inline void 537c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5388d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5395cb1dd27SAsmitha Karunanithi { 540fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 541fdd26906SClaire Weinan if (entriesPath.empty()) 5425cb1dd27SAsmitha Karunanithi { 5435cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5445cb1dd27SAsmitha Karunanithi return; 5455cb1dd27SAsmitha Karunanithi } 5465cb1dd27SAsmitha Karunanithi 5475cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 548fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 549fdd26906SClaire Weinan entriesPath](const boost::system::error_code ec, 55002cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5515cb1dd27SAsmitha Karunanithi if (ec) 5525cb1dd27SAsmitha Karunanithi { 5535cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5545cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5555cb1dd27SAsmitha Karunanithi return; 5565cb1dd27SAsmitha Karunanithi } 5575cb1dd27SAsmitha Karunanithi 558b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 559b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 560b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 561002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 562b47452b2SAsmitha Karunanithi 5639eb808c1SEd Tanous for (const auto& objectPath : resp) 5645cb1dd27SAsmitha Karunanithi { 565b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 5665cb1dd27SAsmitha Karunanithi { 5675cb1dd27SAsmitha Karunanithi continue; 5685cb1dd27SAsmitha Karunanithi } 5695cb1dd27SAsmitha Karunanithi 5705cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 571c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5725cb1dd27SAsmitha Karunanithi uint64_t size = 0; 57335440d18SAsmitha Karunanithi std::string dumpStatus; 5745cb1dd27SAsmitha Karunanithi 575aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 576c6fecdabSClaire Weinan timestampUs, asyncResp); 5775cb1dd27SAsmitha Karunanithi 5780fda0f12SGeorge Liu if (dumpStatus != 5790fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 58035440d18SAsmitha Karunanithi !dumpStatus.empty()) 58135440d18SAsmitha Karunanithi { 58235440d18SAsmitha Karunanithi // Dump status is not Complete 58335440d18SAsmitha Karunanithi // return not found until status is changed to Completed 584d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 585d1bde9e5SKrzysztof Grobelny entryID); 58635440d18SAsmitha Karunanithi return; 58735440d18SAsmitha Karunanithi } 58835440d18SAsmitha Karunanithi 5895cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 5909c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 591fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5925cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 5935cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 5945cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 595*bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 596*bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5975cb1dd27SAsmitha Karunanithi 5985cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5995cb1dd27SAsmitha Karunanithi { 600d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 601d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 602fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 603fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6045cb1dd27SAsmitha Karunanithi } 6055cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6065cb1dd27SAsmitha Karunanithi { 607d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 608002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 609d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 610fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 611fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6125cb1dd27SAsmitha Karunanithi } 6135cb1dd27SAsmitha Karunanithi } 614e05aec50SEd Tanous if (!foundDumpEntry) 615b47452b2SAsmitha Karunanithi { 616b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 617b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 618b47452b2SAsmitha Karunanithi return; 619b47452b2SAsmitha Karunanithi } 6205cb1dd27SAsmitha Karunanithi }, 6215cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6225cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6235cb1dd27SAsmitha Karunanithi } 6245cb1dd27SAsmitha Karunanithi 6258d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6269878256fSStanley Chu const std::string& entryID, 627b47452b2SAsmitha Karunanithi const std::string& dumpType) 6285cb1dd27SAsmitha Karunanithi { 629002d39b4SEd Tanous auto respHandler = 630002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 6315cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6325cb1dd27SAsmitha Karunanithi if (ec) 6335cb1dd27SAsmitha Karunanithi { 6343de8d8baSGeorge Liu if (ec.value() == EBADR) 6353de8d8baSGeorge Liu { 6363de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6373de8d8baSGeorge Liu return; 6383de8d8baSGeorge Liu } 6395cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 640fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6415cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6425cb1dd27SAsmitha Karunanithi return; 6435cb1dd27SAsmitha Karunanithi } 6445cb1dd27SAsmitha Karunanithi }; 6455cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6465cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 647b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 648b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 649b47452b2SAsmitha Karunanithi entryID, 6505cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 6515cb1dd27SAsmitha Karunanithi } 6525cb1dd27SAsmitha Karunanithi 6538e31778eSAsmitha Karunanithi inline DumpCreationProgress 6548e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 655a43be80fSAsmitha Karunanithi { 6568e31778eSAsmitha Karunanithi if (status == 6578e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 6588e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 6598e31778eSAsmitha Karunanithi { 6608e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6618e31778eSAsmitha Karunanithi } 6628e31778eSAsmitha Karunanithi if (status == 6638e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 6648e31778eSAsmitha Karunanithi { 6658e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 6668e31778eSAsmitha Karunanithi } 6678e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 6688e31778eSAsmitha Karunanithi } 6698e31778eSAsmitha Karunanithi 6708e31778eSAsmitha Karunanithi inline DumpCreationProgress 6718e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 6728e31778eSAsmitha Karunanithi { 6738e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 6748e31778eSAsmitha Karunanithi { 6758e31778eSAsmitha Karunanithi if (key == "Status") 6768e31778eSAsmitha Karunanithi { 6778e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 6788e31778eSAsmitha Karunanithi if (value == nullptr) 6798e31778eSAsmitha Karunanithi { 6808e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 6818e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6828e31778eSAsmitha Karunanithi } 6838e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 6848e31778eSAsmitha Karunanithi } 6858e31778eSAsmitha Karunanithi } 6868e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 6878e31778eSAsmitha Karunanithi } 6888e31778eSAsmitha Karunanithi 6898e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 6908e31778eSAsmitha Karunanithi { 6918e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 6928e31778eSAsmitha Karunanithi { 6938e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 6948e31778eSAsmitha Karunanithi } 6958e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 6968e31778eSAsmitha Karunanithi { 6978e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 6988e31778eSAsmitha Karunanithi } 6998e31778eSAsmitha Karunanithi return ""; 7008e31778eSAsmitha Karunanithi } 7018e31778eSAsmitha Karunanithi 7028e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7038e31778eSAsmitha Karunanithi task::Payload&& payload, 7048e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7058e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7068e31778eSAsmitha Karunanithi { 7078e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7088e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7098e31778eSAsmitha Karunanithi 7108e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7118e31778eSAsmitha Karunanithi 7128e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7138e31778eSAsmitha Karunanithi { 7148e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 7158e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7168e31778eSAsmitha Karunanithi return; 7178e31778eSAsmitha Karunanithi } 7188e31778eSAsmitha Karunanithi 7198e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7208e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 7218e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 7228e31778eSAsmitha Karunanithi dumpId](const boost::system::error_code ec, 7238e31778eSAsmitha Karunanithi const std::string& introspectXml) { 7248e31778eSAsmitha Karunanithi if (ec) 7258e31778eSAsmitha Karunanithi { 7268e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 7278e31778eSAsmitha Karunanithi << ec.message(); 7288e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7298e31778eSAsmitha Karunanithi return; 7308e31778eSAsmitha Karunanithi } 7318e31778eSAsmitha Karunanithi 7328e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 7338e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 7348e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 7358e31778eSAsmitha Karunanithi // Else, return task completed. 7368e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 7378e31778eSAsmitha Karunanithi 7388e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 7398e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 7408e31778eSAsmitha Karunanithi if (pRoot == nullptr) 7418e31778eSAsmitha Karunanithi { 7428e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 7438e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7448e31778eSAsmitha Karunanithi return; 7458e31778eSAsmitha Karunanithi } 7468e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 7478e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 7488e31778eSAsmitha Karunanithi 7498e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 7508e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 7518e31778eSAsmitha Karunanithi { 7528e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 7538e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 7548e31778eSAsmitha Karunanithi { 7558e31778eSAsmitha Karunanithi if (thisInterfaceName == 7568e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 7578e31778eSAsmitha Karunanithi { 7588e31778eSAsmitha Karunanithi interfaceNode = 7598e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 7608e31778eSAsmitha Karunanithi continue; 7618e31778eSAsmitha Karunanithi } 7628e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 7638e31778eSAsmitha Karunanithi break; 7648e31778eSAsmitha Karunanithi } 7658e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 7668e31778eSAsmitha Karunanithi } 7678e31778eSAsmitha Karunanithi 768a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 7698e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 7708e31778eSAsmitha Karunanithi boost::system::error_code err, sdbusplus::message::message& msg, 771a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 772cb13a392SEd Tanous if (err) 773cb13a392SEd Tanous { 7748e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 7758e31778eSAsmitha Karunanithi << ": Error in creating dump"; 7768e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 7776145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 7786145ed6fSAsmitha Karunanithi return task::completed; 779cb13a392SEd Tanous } 780b9d36b47SEd Tanous 7818e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 782a43be80fSAsmitha Karunanithi { 7838e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 7848e31778eSAsmitha Karunanithi std::string prop; 7858e31778eSAsmitha Karunanithi msg.read(prop, values); 7868e31778eSAsmitha Karunanithi 7878e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 7888e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 7898e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 7908e31778eSAsmitha Karunanithi { 7918e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 7928e31778eSAsmitha Karunanithi << ": Error in creating dump"; 7938e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 7948e31778eSAsmitha Karunanithi return task::completed; 7958e31778eSAsmitha Karunanithi } 7968e31778eSAsmitha Karunanithi 7978e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 7988e31778eSAsmitha Karunanithi { 7998e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8008e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 8018e31778eSAsmitha Karunanithi return !task::completed; 8028e31778eSAsmitha Karunanithi } 8038e31778eSAsmitha Karunanithi } 8048e31778eSAsmitha Karunanithi 805a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 806a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 807a43be80fSAsmitha Karunanithi 808a43be80fSAsmitha Karunanithi std::string headerLoc = 8098e31778eSAsmitha Karunanithi "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId); 810002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 811a43be80fSAsmitha Karunanithi 8128e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8138e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 814a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 815b47452b2SAsmitha Karunanithi return task::completed; 816a43be80fSAsmitha Karunanithi }, 8178e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 8188e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 8198e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 820a43be80fSAsmitha Karunanithi 8218e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 8228e31778eSAsmitha Karunanithi // requested dump will be collected. 8238e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 824a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 8258e31778eSAsmitha Karunanithi task->payload.emplace(payload); 8268e31778eSAsmitha Karunanithi }, 8278e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 8288e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 829a43be80fSAsmitha Karunanithi } 830a43be80fSAsmitha Karunanithi 8318d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8328d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 833a43be80fSAsmitha Karunanithi { 834fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 835fdd26906SClaire Weinan if (dumpPath.empty()) 836a43be80fSAsmitha Karunanithi { 837a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 838a43be80fSAsmitha Karunanithi return; 839a43be80fSAsmitha Karunanithi } 840a43be80fSAsmitha Karunanithi 841a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 842a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 843a43be80fSAsmitha Karunanithi 84415ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 845a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 846a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 847a43be80fSAsmitha Karunanithi { 848a43be80fSAsmitha Karunanithi return; 849a43be80fSAsmitha Karunanithi } 850a43be80fSAsmitha Karunanithi 851a43be80fSAsmitha Karunanithi if (dumpType == "System") 852a43be80fSAsmitha Karunanithi { 853a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 854a43be80fSAsmitha Karunanithi { 8554978b63fSJason M. Bills BMCWEB_LOG_ERROR 8564978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 857a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 858a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 859a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 860a43be80fSAsmitha Karunanithi return; 861a43be80fSAsmitha Karunanithi } 8623174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 863a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 864a43be80fSAsmitha Karunanithi { 865a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 866ace85d60SEd Tanous messages::internalError(asyncResp->res); 867a43be80fSAsmitha Karunanithi return; 868a43be80fSAsmitha Karunanithi } 8695907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 870a43be80fSAsmitha Karunanithi } 871a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 872a43be80fSAsmitha Karunanithi { 873a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 874a43be80fSAsmitha Karunanithi { 8750fda0f12SGeorge Liu BMCWEB_LOG_ERROR 8760fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 877a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 878a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 879a43be80fSAsmitha Karunanithi return; 880a43be80fSAsmitha Karunanithi } 8813174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 882a43be80fSAsmitha Karunanithi { 883a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 884a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 885ace85d60SEd Tanous messages::internalError(asyncResp->res); 886a43be80fSAsmitha Karunanithi return; 887a43be80fSAsmitha Karunanithi } 8885907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 8895907571dSAsmitha Karunanithi } 8905907571dSAsmitha Karunanithi else 8915907571dSAsmitha Karunanithi { 8925907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 8935907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 8945907571dSAsmitha Karunanithi return; 895a43be80fSAsmitha Karunanithi } 896a43be80fSAsmitha Karunanithi 8978e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 8988e31778eSAsmitha Karunanithi createDumpParamVec; 8998e31778eSAsmitha Karunanithi 900a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9018e31778eSAsmitha Karunanithi [asyncResp, payload(task::Payload(req)), 9028e31778eSAsmitha Karunanithi dumpPath](const boost::system::error_code ec, 9035907571dSAsmitha Karunanithi const sdbusplus::message::message& msg, 9048e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 905a43be80fSAsmitha Karunanithi if (ec) 906a43be80fSAsmitha Karunanithi { 907a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9085907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9095907571dSAsmitha Karunanithi if (dbusError == nullptr) 9105907571dSAsmitha Karunanithi { 9115907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9125907571dSAsmitha Karunanithi return; 9135907571dSAsmitha Karunanithi } 9145907571dSAsmitha Karunanithi 9155907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9165907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9175907571dSAsmitha Karunanithi if (std::string_view( 9185907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9195907571dSAsmitha Karunanithi dbusError->name) 9205907571dSAsmitha Karunanithi { 9215907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9225907571dSAsmitha Karunanithi return; 9235907571dSAsmitha Karunanithi } 9245907571dSAsmitha Karunanithi if (std::string_view( 9255907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9265907571dSAsmitha Karunanithi dbusError->name) 9275907571dSAsmitha Karunanithi { 9285907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9295907571dSAsmitha Karunanithi return; 9305907571dSAsmitha Karunanithi } 9315907571dSAsmitha Karunanithi if (std::string_view( 9325907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9335907571dSAsmitha Karunanithi dbusError->name) 9345907571dSAsmitha Karunanithi { 9355907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 9365907571dSAsmitha Karunanithi return; 9375907571dSAsmitha Karunanithi } 9385907571dSAsmitha Karunanithi // Other Dbus errors such as: 9395907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 9405907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 9415907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 9425907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 9435907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 9445907571dSAsmitha Karunanithi // back to the client. 945a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 946a43be80fSAsmitha Karunanithi return; 947a43be80fSAsmitha Karunanithi } 9488e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 9498e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 950a43be80fSAsmitha Karunanithi }, 951b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 952b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 953b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 9548e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 955a43be80fSAsmitha Karunanithi } 956a43be80fSAsmitha Karunanithi 9578d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9588d1b46d7Szhanghch05 const std::string& dumpType) 95980319af1SAsmitha Karunanithi { 960b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 961b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 9628d1b46d7Szhanghch05 96380319af1SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 964b9d36b47SEd Tanous [asyncResp, dumpType]( 965b9d36b47SEd Tanous const boost::system::error_code ec, 966b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 96780319af1SAsmitha Karunanithi if (ec) 96880319af1SAsmitha Karunanithi { 96980319af1SAsmitha Karunanithi BMCWEB_LOG_ERROR << "resp_handler got error " << ec; 97080319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 97180319af1SAsmitha Karunanithi return; 97280319af1SAsmitha Karunanithi } 97380319af1SAsmitha Karunanithi 97480319af1SAsmitha Karunanithi for (const std::string& path : subTreePaths) 97580319af1SAsmitha Karunanithi { 9762dfd18efSEd Tanous sdbusplus::message::object_path objPath(path); 9772dfd18efSEd Tanous std::string logID = objPath.filename(); 9782dfd18efSEd Tanous if (logID.empty()) 97980319af1SAsmitha Karunanithi { 9802dfd18efSEd Tanous continue; 98180319af1SAsmitha Karunanithi } 9822dfd18efSEd Tanous deleteDumpEntry(asyncResp, logID, dumpType); 98380319af1SAsmitha Karunanithi } 98480319af1SAsmitha Karunanithi }, 98580319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", 98680319af1SAsmitha Karunanithi "/xyz/openbmc_project/object_mapper", 98780319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 988b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, 989b47452b2SAsmitha Karunanithi std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." + 990b47452b2SAsmitha Karunanithi dumpType}); 99180319af1SAsmitha Karunanithi } 99280319af1SAsmitha Karunanithi 993b9d36b47SEd Tanous inline static void 994b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 995b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 996b9d36b47SEd Tanous std::string& logfile) 997043a0536SJohnathan Mantey { 998d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 999d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1000d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1001d1bde9e5SKrzysztof Grobelny 1002d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1003d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1004d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1005d1bde9e5SKrzysztof Grobelny 1006d1bde9e5SKrzysztof Grobelny if (!success) 1007043a0536SJohnathan Mantey { 1008d1bde9e5SKrzysztof Grobelny return; 1009043a0536SJohnathan Mantey } 1010d1bde9e5SKrzysztof Grobelny 1011d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1012043a0536SJohnathan Mantey { 1013d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1014d1bde9e5SKrzysztof Grobelny } 1015d1bde9e5SKrzysztof Grobelny 1016d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1017043a0536SJohnathan Mantey { 1018d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1019043a0536SJohnathan Mantey } 1020d1bde9e5SKrzysztof Grobelny 1021d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1022043a0536SJohnathan Mantey { 1023d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1024043a0536SJohnathan Mantey } 1025043a0536SJohnathan Mantey } 1026043a0536SJohnathan Mantey 1027a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode"; 10287e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10291da66f75SEd Tanous { 1030c4bf6374SJason M. Bills /** 1031c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1032c4bf6374SJason M. Bills */ 103322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1034ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1035002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1036002d39b4SEd Tanous [&app](const crow::Request& req, 103722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 103822d268cbSEd Tanous const std::string& systemName) { 10393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1040c4bf6374SJason M. Bills { 104145ca1b86SEd Tanous return; 104245ca1b86SEd Tanous } 104322d268cbSEd Tanous if (systemName != "system") 104422d268cbSEd Tanous { 104522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 104622d268cbSEd Tanous systemName); 104722d268cbSEd Tanous return; 104822d268cbSEd Tanous } 104922d268cbSEd Tanous 10507e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10517e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1052c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1053c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1054c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1055029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 105645ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1057c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1058c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1059002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1060c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 10611476687dSEd Tanous nlohmann::json::object_t eventLog; 10621476687dSEd Tanous eventLog["@odata.id"] = 10631476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 10641476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 10655cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 10661476687dSEd Tanous nlohmann::json::object_t dumpLog; 1067002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 10681476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 1069c9bb6861Sraviteja-b #endif 1070c9bb6861Sraviteja-b 1071d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 10721476687dSEd Tanous nlohmann::json::object_t crashdump; 10731476687dSEd Tanous crashdump["@odata.id"] = 10741476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 10751476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 1076d53dd41fSJason M. Bills #endif 1077b7028ebfSSpencer Ku 1078b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 10791476687dSEd Tanous nlohmann::json::object_t hostlogger; 10801476687dSEd Tanous hostlogger["@odata.id"] = 10811476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 10821476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 1083b7028ebfSSpencer Ku #endif 1084c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1085c4bf6374SJason M. Bills logServiceArray.size(); 1086a3316fc6SZhikuiRen 1087a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 108845ca1b86SEd Tanous [asyncResp](const boost::system::error_code ec, 1089b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1090b9d36b47SEd Tanous subtreePath) { 1091a3316fc6SZhikuiRen if (ec) 1092a3316fc6SZhikuiRen { 1093a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 1094a3316fc6SZhikuiRen return; 1095a3316fc6SZhikuiRen } 1096a3316fc6SZhikuiRen 109755f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1098a3316fc6SZhikuiRen { 1099a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1100a3316fc6SZhikuiRen { 110123a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1102a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1103613dabeaSEd Tanous nlohmann::json::object_t member; 1104613dabeaSEd Tanous member["@odata.id"] = 1105613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1106613dabeaSEd Tanous 1107613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 1108613dabeaSEd Tanous 110945ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 111023a21a1cSEd Tanous logServiceArrayLocal.size(); 1111a3316fc6SZhikuiRen return; 1112a3316fc6SZhikuiRen } 1113a3316fc6SZhikuiRen } 1114a3316fc6SZhikuiRen }, 1115a3316fc6SZhikuiRen "xyz.openbmc_project.ObjectMapper", 1116a3316fc6SZhikuiRen "/xyz/openbmc_project/object_mapper", 111745ca1b86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0, 111845ca1b86SEd Tanous std::array<const char*, 1>{postCodeIface}); 11197e860f15SJohn Edward Broadbent }); 1120c4bf6374SJason M. Bills } 1121c4bf6374SJason M. Bills 11227e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1123c4bf6374SJason M. Bills { 112422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1125ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1126002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1127002d39b4SEd Tanous [&app](const crow::Request& req, 112822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 112922d268cbSEd Tanous const std::string& systemName) { 11303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 113145ca1b86SEd Tanous { 113245ca1b86SEd Tanous return; 113345ca1b86SEd Tanous } 113422d268cbSEd Tanous if (systemName != "system") 113522d268cbSEd Tanous { 113622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 113722d268cbSEd Tanous systemName); 113822d268cbSEd Tanous return; 113922d268cbSEd Tanous } 1140c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1141029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1142c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1143c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1144c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1145002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1146c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1147c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11487c8c4058STejas Patil 11497c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11502b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11517c8c4058STejas Patil 11527c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 11537c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 11547c8c4058STejas Patil redfishDateTimeOffset.second; 11557c8c4058STejas Patil 11561476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 11571476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1158e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1159e7d6c8b2SGunnar Mills 11600fda0f12SGeorge Liu {"target", 11610fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 11627e860f15SJohn Edward Broadbent }); 1163489640c6SJason M. Bills } 1164489640c6SJason M. Bills 11657e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1166489640c6SJason M. Bills { 11674978b63fSJason M. Bills BMCWEB_ROUTE( 11684978b63fSJason M. Bills app, 116922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1170432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 11717e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 117245ca1b86SEd Tanous [&app](const crow::Request& req, 117322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 117422d268cbSEd Tanous const std::string& systemName) { 11753ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117645ca1b86SEd Tanous { 117745ca1b86SEd Tanous return; 117845ca1b86SEd Tanous } 117922d268cbSEd Tanous if (systemName != "system") 118022d268cbSEd Tanous { 118122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 118222d268cbSEd Tanous systemName); 118322d268cbSEd Tanous return; 118422d268cbSEd Tanous } 1185489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1186489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1187489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1188489640c6SJason M. Bills { 1189489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1190489640c6SJason M. Bills { 1191489640c6SJason M. Bills std::error_code ec; 1192489640c6SJason M. Bills std::filesystem::remove(file, ec); 1193489640c6SJason M. Bills } 1194489640c6SJason M. Bills } 1195489640c6SJason M. Bills 1196489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1197489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 1198489640c6SJason M. Bills [asyncResp](const boost::system::error_code ec) { 1199489640c6SJason M. Bills if (ec) 1200489640c6SJason M. Bills { 1201002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1202489640c6SJason M. Bills messages::internalError(asyncResp->res); 1203489640c6SJason M. Bills return; 1204489640c6SJason M. Bills } 1205489640c6SJason M. Bills 1206489640c6SJason M. Bills messages::success(asyncResp->res); 1207489640c6SJason M. Bills }, 1208489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1209002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1210002d39b4SEd Tanous "replace"); 12117e860f15SJohn Edward Broadbent }); 1212c4bf6374SJason M. Bills } 1213c4bf6374SJason M. Bills 1214ac992cdeSJason M. Bills enum class LogParseError 1215ac992cdeSJason M. Bills { 1216ac992cdeSJason M. Bills success, 1217ac992cdeSJason M. Bills parseFailed, 1218ac992cdeSJason M. Bills messageIdNotInRegistry, 1219ac992cdeSJason M. Bills }; 1220ac992cdeSJason M. Bills 1221ac992cdeSJason M. Bills static LogParseError 1222ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1223b5a76932SEd Tanous const std::string& logEntry, 1224de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1225c4bf6374SJason M. Bills { 122695820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1227cd225da8SJason M. Bills // First get the Timestamp 1228f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1229cd225da8SJason M. Bills if (space == std::string::npos) 123095820184SJason M. Bills { 1231ac992cdeSJason M. Bills return LogParseError::parseFailed; 123295820184SJason M. Bills } 1233cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1234cd225da8SJason M. Bills // Then get the log contents 1235f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1236cd225da8SJason M. Bills if (entryStart == std::string::npos) 1237cd225da8SJason M. Bills { 1238ac992cdeSJason M. Bills return LogParseError::parseFailed; 1239cd225da8SJason M. Bills } 1240cd225da8SJason M. Bills std::string_view entry(logEntry); 1241cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1242cd225da8SJason M. Bills // Use split to separate the entry into its fields 1243cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 1244cd225da8SJason M. Bills boost::split(logEntryFields, entry, boost::is_any_of(","), 1245cd225da8SJason M. Bills boost::token_compress_on); 1246cd225da8SJason M. Bills // We need at least a MessageId to be valid 124726f6976fSEd Tanous if (logEntryFields.empty()) 1248cd225da8SJason M. Bills { 1249ac992cdeSJason M. Bills return LogParseError::parseFailed; 1250cd225da8SJason M. Bills } 1251cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 125295820184SJason M. Bills 12534851d45dSJason M. Bills // Get the Message from the MessageRegistry 1254fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1255c4bf6374SJason M. Bills 125654417b02SSui Chen if (message == nullptr) 1257c4bf6374SJason M. Bills { 125854417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1259ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1260c4bf6374SJason M. Bills } 1261c4bf6374SJason M. Bills 126254417b02SSui Chen std::string msg = message->message; 126354417b02SSui Chen 126415a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 126526702d01SEd Tanous std::span<std::string> messageArgs; 126615a86ff6SJason M. Bills if (logEntryFields.size() > 1) 126715a86ff6SJason M. Bills { 126815a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 126915a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 127015a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 127115a86ff6SJason M. Bills if (!messageArgsStart.empty()) 127215a86ff6SJason M. Bills { 127315a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 127415a86ff6SJason M. Bills } 127515a86ff6SJason M. Bills 127623a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1277c4bf6374SJason M. Bills 12784851d45dSJason M. Bills // Fill the MessageArgs into the Message 127995820184SJason M. Bills int i = 0; 128095820184SJason M. Bills for (const std::string& messageArg : messageArgs) 12814851d45dSJason M. Bills { 128295820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 12834851d45dSJason M. Bills size_t argPos = msg.find(argStr); 12844851d45dSJason M. Bills if (argPos != std::string::npos) 12854851d45dSJason M. Bills { 128695820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 12874851d45dSJason M. Bills } 12884851d45dSJason M. Bills } 128915a86ff6SJason M. Bills } 12904851d45dSJason M. Bills 129195820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 129295820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 129395820184SJason M. Bills // between the '.' and the '+', so just remove them. 1294f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1295f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 129695820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1297c4bf6374SJason M. Bills { 129895820184SJason M. Bills timestamp.erase(dot, plus - dot); 1299c4bf6374SJason M. Bills } 1300c4bf6374SJason M. Bills 1301c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13029c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 130384afc48bSJason M. Bills logEntryJson["@odata.id"] = 130484afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID; 130584afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 130684afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 130784afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 130884afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 130984afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 131084afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 131184afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 131284afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1313ac992cdeSJason M. Bills return LogParseError::success; 1314c4bf6374SJason M. Bills } 1315c4bf6374SJason M. Bills 13167e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1317c4bf6374SJason M. Bills { 131822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13198b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1320002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1321002d39b4SEd Tanous [&app](const crow::Request& req, 132222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 132322d268cbSEd Tanous const std::string& systemName) { 1324c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1325c937d2bfSEd Tanous .canDelegateTop = true, 1326c937d2bfSEd Tanous .canDelegateSkip = true, 1327c937d2bfSEd Tanous }; 1328c937d2bfSEd Tanous query_param::Query delegatedQuery; 1329c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13303ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1331c4bf6374SJason M. Bills { 1332c4bf6374SJason M. Bills return; 1333c4bf6374SJason M. Bills } 133422d268cbSEd Tanous if (systemName != "system") 133522d268cbSEd Tanous { 133622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 133722d268cbSEd Tanous systemName); 133822d268cbSEd Tanous return; 133922d268cbSEd Tanous } 134022d268cbSEd Tanous 13415143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13423648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13433648c8beSEd Tanous 13447e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13457e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1346c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1347c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1348c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1349029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1350c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1351c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1352c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1353cb92c03bSAndrew Geissler 13544978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1355c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13567e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13577e860f15SJohn Edward Broadbent // entry 135895820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 135995820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1360b01bf299SEd Tanous uint64_t entryCount = 0; 1361cd225da8SJason M. Bills std::string logEntry; 136295820184SJason M. Bills 13637e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13647e860f15SJohn Edward Broadbent // backwards 1365002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1366002d39b4SEd Tanous it++) 1367c4bf6374SJason M. Bills { 1368cd225da8SJason M. Bills std::ifstream logStream(*it); 136995820184SJason M. Bills if (!logStream.is_open()) 1370c4bf6374SJason M. Bills { 1371c4bf6374SJason M. Bills continue; 1372c4bf6374SJason M. Bills } 1373c4bf6374SJason M. Bills 1374e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1375e85d6b16SJason M. Bills bool firstEntry = true; 137695820184SJason M. Bills while (std::getline(logStream, logEntry)) 137795820184SJason M. Bills { 1378c4bf6374SJason M. Bills std::string idStr; 1379e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1380c4bf6374SJason M. Bills { 1381c4bf6374SJason M. Bills continue; 1382c4bf6374SJason M. Bills } 1383e85d6b16SJason M. Bills firstEntry = false; 1384e85d6b16SJason M. Bills 1385de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1386ac992cdeSJason M. Bills LogParseError status = 1387ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1388ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1389ac992cdeSJason M. Bills { 1390ac992cdeSJason M. Bills continue; 1391ac992cdeSJason M. Bills } 1392ac992cdeSJason M. Bills if (status != LogParseError::success) 1393c4bf6374SJason M. Bills { 1394c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1395c4bf6374SJason M. Bills return; 1396c4bf6374SJason M. Bills } 1397de703c5dSJason M. Bills 1398de703c5dSJason M. Bills entryCount++; 1399de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1400de703c5dSJason M. Bills // start) and top (number of entries to display) 14013648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1402de703c5dSJason M. Bills { 1403de703c5dSJason M. Bills continue; 1404de703c5dSJason M. Bills } 1405de703c5dSJason M. Bills 1406de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1407c4bf6374SJason M. Bills } 140895820184SJason M. Bills } 1409c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14103648c8beSEd Tanous if (skip + top < entryCount) 1411c4bf6374SJason M. Bills { 1412c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14134978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14143648c8beSEd Tanous std::to_string(skip + top); 1415c4bf6374SJason M. Bills } 14167e860f15SJohn Edward Broadbent }); 1417897967deSJason M. Bills } 1418897967deSJason M. Bills 14197e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1420897967deSJason M. Bills { 14217e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 142222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1423ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14247e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 142545ca1b86SEd Tanous [&app](const crow::Request& req, 14267e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 142722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14283ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 142945ca1b86SEd Tanous { 143045ca1b86SEd Tanous return; 143145ca1b86SEd Tanous } 143222d268cbSEd Tanous 143322d268cbSEd Tanous if (systemName != "system") 143422d268cbSEd Tanous { 143522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 143622d268cbSEd Tanous systemName); 143722d268cbSEd Tanous return; 143822d268cbSEd Tanous } 143922d268cbSEd Tanous 14407e860f15SJohn Edward Broadbent const std::string& targetID = param; 14418d1b46d7Szhanghch05 14427e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14437e860f15SJohn Edward Broadbent // entry to find the target entry 1444897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1445897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1446897967deSJason M. Bills std::string logEntry; 1447897967deSJason M. Bills 14487e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14497e860f15SJohn Edward Broadbent // backwards 1450002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1451002d39b4SEd Tanous it++) 1452897967deSJason M. Bills { 1453897967deSJason M. Bills std::ifstream logStream(*it); 1454897967deSJason M. Bills if (!logStream.is_open()) 1455897967deSJason M. Bills { 1456897967deSJason M. Bills continue; 1457897967deSJason M. Bills } 1458897967deSJason M. Bills 1459897967deSJason M. Bills // Reset the unique ID on the first entry 1460897967deSJason M. Bills bool firstEntry = true; 1461897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1462897967deSJason M. Bills { 1463897967deSJason M. Bills std::string idStr; 1464897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1465897967deSJason M. Bills { 1466897967deSJason M. Bills continue; 1467897967deSJason M. Bills } 1468897967deSJason M. Bills firstEntry = false; 1469897967deSJason M. Bills 1470897967deSJason M. Bills if (idStr == targetID) 1471897967deSJason M. Bills { 1472de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1473ac992cdeSJason M. Bills LogParseError status = 1474ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1475ac992cdeSJason M. Bills if (status != LogParseError::success) 1476897967deSJason M. Bills { 1477897967deSJason M. Bills messages::internalError(asyncResp->res); 1478897967deSJason M. Bills return; 1479897967deSJason M. Bills } 1480d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1481897967deSJason M. Bills return; 1482897967deSJason M. Bills } 1483897967deSJason M. Bills } 1484897967deSJason M. Bills } 1485897967deSJason M. Bills // Requested ID was not found 14869db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 14877e860f15SJohn Edward Broadbent }); 148808a4e4b5SAnthony Wilson } 148908a4e4b5SAnthony Wilson 14907e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 149108a4e4b5SAnthony Wilson { 149222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1493ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1494002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1495002d39b4SEd Tanous [&app](const crow::Request& req, 149622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 149722d268cbSEd Tanous const std::string& systemName) { 14983ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 149945ca1b86SEd Tanous { 150045ca1b86SEd Tanous return; 150145ca1b86SEd Tanous } 150222d268cbSEd Tanous if (systemName != "system") 150322d268cbSEd Tanous { 150422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 150522d268cbSEd Tanous systemName); 150622d268cbSEd Tanous return; 150722d268cbSEd Tanous } 150822d268cbSEd Tanous 15097e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15107e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 151108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 151208a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 151308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 151408a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 151508a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 151608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 151708a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 151808a4e4b5SAnthony Wilson 1519cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1520cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1521cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 1522cb92c03bSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1523914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1524cb92c03bSAndrew Geissler if (ec) 1525cb92c03bSAndrew Geissler { 1526cb92c03bSAndrew Geissler // TODO Handle for specific error code 1527cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1528002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1529cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1530cb92c03bSAndrew Geissler return; 1531cb92c03bSAndrew Geissler } 1532002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1533cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15349eb808c1SEd Tanous for (const auto& objectPath : resp) 1535cb92c03bSAndrew Geissler { 1536914e2d5dSEd Tanous const uint32_t* id = nullptr; 1537c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1538c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1539914e2d5dSEd Tanous const std::string* severity = nullptr; 1540914e2d5dSEd Tanous const std::string* message = nullptr; 1541914e2d5dSEd Tanous const std::string* filePath = nullptr; 15429c11a172SVijay Lobo const std::string* resolution = nullptr; 154375710de2SXiaochao Ma bool resolved = false; 15449eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1545f86bb901SAdriana Kobylak { 1546f86bb901SAdriana Kobylak if (interfaceMap.first == 1547f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1548f86bb901SAdriana Kobylak { 1549002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1550cb92c03bSAndrew Geissler { 1551cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1552cb92c03bSAndrew Geissler { 1553002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1554cb92c03bSAndrew Geissler } 1555cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1556cb92c03bSAndrew Geissler { 1557002d39b4SEd Tanous timestamp = 1558002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15597e860f15SJohn Edward Broadbent } 1560002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 15617e860f15SJohn Edward Broadbent { 1562002d39b4SEd Tanous updateTimestamp = 1563002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15647e860f15SJohn Edward Broadbent } 15657e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 15667e860f15SJohn Edward Broadbent { 15677e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 15687e860f15SJohn Edward Broadbent &propertyMap.second); 15697e860f15SJohn Edward Broadbent } 15709c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 15719c11a172SVijay Lobo { 15729c11a172SVijay Lobo resolution = std::get_if<std::string>( 15739c11a172SVijay Lobo &propertyMap.second); 15749c11a172SVijay Lobo } 15757e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 15767e860f15SJohn Edward Broadbent { 15777e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 15787e860f15SJohn Edward Broadbent &propertyMap.second); 15797e860f15SJohn Edward Broadbent } 15807e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 15817e860f15SJohn Edward Broadbent { 1582914e2d5dSEd Tanous const bool* resolveptr = 1583002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 15847e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 15857e860f15SJohn Edward Broadbent { 1586002d39b4SEd Tanous messages::internalError(asyncResp->res); 15877e860f15SJohn Edward Broadbent return; 15887e860f15SJohn Edward Broadbent } 15897e860f15SJohn Edward Broadbent resolved = *resolveptr; 15907e860f15SJohn Edward Broadbent } 15917e860f15SJohn Edward Broadbent } 15927e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 15937e860f15SJohn Edward Broadbent severity == nullptr) 15947e860f15SJohn Edward Broadbent { 15957e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 15967e860f15SJohn Edward Broadbent return; 15977e860f15SJohn Edward Broadbent } 15987e860f15SJohn Edward Broadbent } 15997e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16007e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16017e860f15SJohn Edward Broadbent { 1602002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16037e860f15SJohn Edward Broadbent { 16047e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16057e860f15SJohn Edward Broadbent { 16067e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16077e860f15SJohn Edward Broadbent &propertyMap.second); 16087e860f15SJohn Edward Broadbent } 16097e860f15SJohn Edward Broadbent } 16107e860f15SJohn Edward Broadbent } 16117e860f15SJohn Edward Broadbent } 16127e860f15SJohn Edward Broadbent // Object path without the 16137e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16147e860f15SJohn Edward Broadbent // and continue. 16157e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1616c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1617c419c759SEd Tanous updateTimestamp == nullptr) 16187e860f15SJohn Edward Broadbent { 16197e860f15SJohn Edward Broadbent continue; 16207e860f15SJohn Edward Broadbent } 16217e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16227e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16239c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 16247e860f15SJohn Edward Broadbent thisEntry["@odata.id"] = 16250fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16267e860f15SJohn Edward Broadbent std::to_string(*id); 16277e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16287e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16297e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16307e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16319c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16329c11a172SVijay Lobo { 16339c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16349c11a172SVijay Lobo } 16357e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16367e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16377e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16387e860f15SJohn Edward Broadbent thisEntry["Created"] = 16392b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 16407e860f15SJohn Edward Broadbent thisEntry["Modified"] = 16412b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 16427e860f15SJohn Edward Broadbent if (filePath != nullptr) 16437e860f15SJohn Edward Broadbent { 16447e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 16450fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16467e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 16477e860f15SJohn Edward Broadbent } 16487e860f15SJohn Edward Broadbent } 1649002d39b4SEd Tanous std::sort( 1650002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1651002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 16527e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 16537e860f15SJohn Edward Broadbent }); 16547e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 16557e860f15SJohn Edward Broadbent entriesArray.size(); 16567e860f15SJohn Edward Broadbent }, 16577e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 16587e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 16597e860f15SJohn Edward Broadbent }); 16607e860f15SJohn Edward Broadbent } 16617e860f15SJohn Edward Broadbent 16627e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 16637e860f15SJohn Edward Broadbent { 16647e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 166522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1666ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1667002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1668002d39b4SEd Tanous [&app](const crow::Request& req, 16697e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 167022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 16727e860f15SJohn Edward Broadbent { 167345ca1b86SEd Tanous return; 167445ca1b86SEd Tanous } 167522d268cbSEd Tanous if (systemName != "system") 167622d268cbSEd Tanous { 167722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 167822d268cbSEd Tanous systemName); 167922d268cbSEd Tanous return; 168022d268cbSEd Tanous } 168122d268cbSEd Tanous 16827e860f15SJohn Edward Broadbent std::string entryID = param; 16837e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 16847e860f15SJohn Edward Broadbent 16857e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 16867e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1687d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1688d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1689d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 1690002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1691b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 16927e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 16937e860f15SJohn Edward Broadbent { 1694d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1695d1bde9e5SKrzysztof Grobelny entryID); 16967e860f15SJohn Edward Broadbent return; 16977e860f15SJohn Edward Broadbent } 16987e860f15SJohn Edward Broadbent if (ec) 16997e860f15SJohn Edward Broadbent { 17000fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1701002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17027e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17037e860f15SJohn Edward Broadbent return; 17047e860f15SJohn Edward Broadbent } 1705914e2d5dSEd Tanous const uint32_t* id = nullptr; 1706c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1707c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1708914e2d5dSEd Tanous const std::string* severity = nullptr; 1709914e2d5dSEd Tanous const std::string* message = nullptr; 1710914e2d5dSEd Tanous const std::string* filePath = nullptr; 17119c11a172SVijay Lobo const std::string* resolution = nullptr; 17127e860f15SJohn Edward Broadbent bool resolved = false; 17137e860f15SJohn Edward Broadbent 1714d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1715d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1716d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17179c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 17189c11a172SVijay Lobo "Resolution", resolution, "Path", filePath); 1719d1bde9e5SKrzysztof Grobelny 1720d1bde9e5SKrzysztof Grobelny if (!success) 172175710de2SXiaochao Ma { 172275710de2SXiaochao Ma messages::internalError(asyncResp->res); 172375710de2SXiaochao Ma return; 172475710de2SXiaochao Ma } 1725d1bde9e5SKrzysztof Grobelny 1726002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 1727002d39b4SEd Tanous timestamp == nullptr || updateTimestamp == nullptr) 1728f86bb901SAdriana Kobylak { 1729ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1730271584abSEd Tanous return; 1731271584abSEd Tanous } 1732f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17339c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1734f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 17350fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1736f86bb901SAdriana Kobylak std::to_string(*id); 173745ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1738f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1739f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1740f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 17419c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17429c11a172SVijay Lobo { 17439c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 17449c11a172SVijay Lobo } 1745f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1746f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1747f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1748f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 17492b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1750f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 17512b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1752f86bb901SAdriana Kobylak if (filePath != nullptr) 1753f86bb901SAdriana Kobylak { 1754f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1755e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1756e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1757f86bb901SAdriana Kobylak } 1758d1bde9e5SKrzysztof Grobelny }); 17597e860f15SJohn Edward Broadbent }); 1760336e96c6SChicago Duan 17617e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 176222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1763ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 17647e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 176545ca1b86SEd Tanous [&app](const crow::Request& req, 17667e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 176722d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 17683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 176945ca1b86SEd Tanous { 177045ca1b86SEd Tanous return; 177145ca1b86SEd Tanous } 177222d268cbSEd Tanous if (systemName != "system") 177322d268cbSEd Tanous { 177422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 177522d268cbSEd Tanous systemName); 177622d268cbSEd Tanous return; 177722d268cbSEd Tanous } 177875710de2SXiaochao Ma std::optional<bool> resolved; 177975710de2SXiaochao Ma 178015ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 17817e860f15SJohn Edward Broadbent resolved)) 178275710de2SXiaochao Ma { 178375710de2SXiaochao Ma return; 178475710de2SXiaochao Ma } 178575710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 178675710de2SXiaochao Ma 178775710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 17884f48d5f6SEd Tanous [asyncResp, entryId](const boost::system::error_code ec) { 178975710de2SXiaochao Ma if (ec) 179075710de2SXiaochao Ma { 179175710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 179275710de2SXiaochao Ma messages::internalError(asyncResp->res); 179375710de2SXiaochao Ma return; 179475710de2SXiaochao Ma } 179575710de2SXiaochao Ma }, 179675710de2SXiaochao Ma "xyz.openbmc_project.Logging", 179775710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 179875710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 179975710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1800168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18017e860f15SJohn Edward Broadbent }); 180275710de2SXiaochao Ma 18037e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 180422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1805ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1806ed398213SEd Tanous 1807002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1808002d39b4SEd Tanous [&app](const crow::Request& req, 1809002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 181022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1812336e96c6SChicago Duan { 181345ca1b86SEd Tanous return; 181445ca1b86SEd Tanous } 181522d268cbSEd Tanous if (systemName != "system") 181622d268cbSEd Tanous { 181722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 181822d268cbSEd Tanous systemName); 181922d268cbSEd Tanous return; 182022d268cbSEd Tanous } 1821336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1822336e96c6SChicago Duan 18237e860f15SJohn Edward Broadbent std::string entryID = param; 1824336e96c6SChicago Duan 1825336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1826336e96c6SChicago Duan 1827336e96c6SChicago Duan // Process response from Logging service. 1828002d39b4SEd Tanous auto respHandler = 1829002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 1830002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1831336e96c6SChicago Duan if (ec) 1832336e96c6SChicago Duan { 18333de8d8baSGeorge Liu if (ec.value() == EBADR) 18343de8d8baSGeorge Liu { 183545ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 183645ca1b86SEd Tanous entryID); 18373de8d8baSGeorge Liu return; 18383de8d8baSGeorge Liu } 1839336e96c6SChicago Duan // TODO Handle for specific error code 18400fda0f12SGeorge Liu BMCWEB_LOG_ERROR 18410fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1842336e96c6SChicago Duan << ec; 1843336e96c6SChicago Duan asyncResp->res.result( 1844336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1845336e96c6SChicago Duan return; 1846336e96c6SChicago Duan } 1847336e96c6SChicago Duan 1848336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1849336e96c6SChicago Duan }; 1850336e96c6SChicago Duan 1851336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1852336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1853336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1854336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1855336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 18567e860f15SJohn Edward Broadbent }); 1857400fd1fbSAdriana Kobylak } 1858400fd1fbSAdriana Kobylak 18597e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1860400fd1fbSAdriana Kobylak { 18610fda0f12SGeorge Liu BMCWEB_ROUTE( 18620fda0f12SGeorge Liu app, 186322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1864ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 18657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 186645ca1b86SEd Tanous [&app](const crow::Request& req, 18677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 186822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 18707e860f15SJohn Edward Broadbent { 187145ca1b86SEd Tanous return; 187245ca1b86SEd Tanous } 187399351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 187499351cd8SEd Tanous req.getHeaderValue("Accept"), 18754a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1876400fd1fbSAdriana Kobylak { 1877002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1878400fd1fbSAdriana Kobylak return; 1879400fd1fbSAdriana Kobylak } 188022d268cbSEd Tanous if (systemName != "system") 188122d268cbSEd Tanous { 188222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 188322d268cbSEd Tanous systemName); 188422d268cbSEd Tanous return; 188522d268cbSEd Tanous } 1886400fd1fbSAdriana Kobylak 18877e860f15SJohn Edward Broadbent std::string entryID = param; 1888400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1889400fd1fbSAdriana Kobylak 1890400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 1891002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1892400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1893400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1894400fd1fbSAdriana Kobylak { 1895002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1896002d39b4SEd Tanous entryID); 1897400fd1fbSAdriana Kobylak return; 1898400fd1fbSAdriana Kobylak } 1899400fd1fbSAdriana Kobylak if (ec) 1900400fd1fbSAdriana Kobylak { 1901400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1902400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1903400fd1fbSAdriana Kobylak return; 1904400fd1fbSAdriana Kobylak } 1905400fd1fbSAdriana Kobylak 1906400fd1fbSAdriana Kobylak int fd = -1; 1907400fd1fbSAdriana Kobylak fd = dup(unixfd); 1908400fd1fbSAdriana Kobylak if (fd == -1) 1909400fd1fbSAdriana Kobylak { 1910400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1911400fd1fbSAdriana Kobylak return; 1912400fd1fbSAdriana Kobylak } 1913400fd1fbSAdriana Kobylak 1914400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1915400fd1fbSAdriana Kobylak if (size == -1) 1916400fd1fbSAdriana Kobylak { 1917400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1918400fd1fbSAdriana Kobylak return; 1919400fd1fbSAdriana Kobylak } 1920400fd1fbSAdriana Kobylak 1921400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1922400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1923400fd1fbSAdriana Kobylak if (size > maxFileSize) 1924400fd1fbSAdriana Kobylak { 1925002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1926400fd1fbSAdriana Kobylak << maxFileSize; 1927400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1928400fd1fbSAdriana Kobylak return; 1929400fd1fbSAdriana Kobylak } 1930400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1931400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1932400fd1fbSAdriana Kobylak if (rc == -1) 1933400fd1fbSAdriana Kobylak { 1934400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1935400fd1fbSAdriana Kobylak return; 1936400fd1fbSAdriana Kobylak } 1937400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1938400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1939400fd1fbSAdriana Kobylak { 1940400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1941400fd1fbSAdriana Kobylak return; 1942400fd1fbSAdriana Kobylak } 1943400fd1fbSAdriana Kobylak close(fd); 1944400fd1fbSAdriana Kobylak 1945400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 1946002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 1947400fd1fbSAdriana Kobylak 1948d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 1949400fd1fbSAdriana Kobylak "application/octet-stream"); 1950d9f6c621SEd Tanous asyncResp->res.addHeader( 1951d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 1952400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 1953400fd1fbSAdriana Kobylak }, 1954400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 1955400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 1956400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 19577e860f15SJohn Edward Broadbent }); 19581da66f75SEd Tanous } 19591da66f75SEd Tanous 1960b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 1961b7028ebfSSpencer Ku 1962b7028ebfSSpencer Ku inline bool 1963b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 1964b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 1965b7028ebfSSpencer Ku { 1966b7028ebfSSpencer Ku std::error_code ec; 1967b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 1968b7028ebfSSpencer Ku if (ec) 1969b7028ebfSSpencer Ku { 1970b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 1971b7028ebfSSpencer Ku return false; 1972b7028ebfSSpencer Ku } 1973b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 1974b7028ebfSSpencer Ku { 1975b7028ebfSSpencer Ku std::string filename = it.path().filename(); 1976b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 1977b7028ebfSSpencer Ku // path 197811ba3979SEd Tanous if (filename.starts_with("log")) 1979b7028ebfSSpencer Ku { 1980b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 1981b7028ebfSSpencer Ku } 1982b7028ebfSSpencer Ku } 1983b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 1984b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 1985b7028ebfSSpencer Ku // descending order. 1986b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 1987b7028ebfSSpencer Ku AlphanumLess<std::string>()); 1988b7028ebfSSpencer Ku 1989b7028ebfSSpencer Ku return true; 1990b7028ebfSSpencer Ku } 1991b7028ebfSSpencer Ku 199202cad96eSEd Tanous inline bool getHostLoggerEntries( 199302cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 199402cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 1995b7028ebfSSpencer Ku { 1996b7028ebfSSpencer Ku GzFileReader logFile; 1997b7028ebfSSpencer Ku 1998b7028ebfSSpencer Ku // Go though all log files and expose host logs. 1999b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2000b7028ebfSSpencer Ku { 2001b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2002b7028ebfSSpencer Ku { 2003b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2004b7028ebfSSpencer Ku return false; 2005b7028ebfSSpencer Ku } 2006b7028ebfSSpencer Ku } 2007b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2008b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2009b7028ebfSSpencer Ku if (!lastMessage.empty()) 2010b7028ebfSSpencer Ku { 2011b7028ebfSSpencer Ku logCount++; 2012b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2013b7028ebfSSpencer Ku { 2014b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2015b7028ebfSSpencer Ku } 2016b7028ebfSSpencer Ku } 2017b7028ebfSSpencer Ku return true; 2018b7028ebfSSpencer Ku } 2019b7028ebfSSpencer Ku 2020b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2021b7028ebfSSpencer Ku const std::string& msg, 20226d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2023b7028ebfSSpencer Ku { 2024b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20259c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 20266d6574c9SJason M. Bills logEntryJson["@odata.id"] = 2027b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" + 20286d6574c9SJason M. Bills logEntryID; 20296d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20306d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20316d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20326d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20336d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20346d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2035b7028ebfSSpencer Ku } 2036b7028ebfSSpencer Ku 2037b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2038b7028ebfSSpencer Ku { 203922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2040b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20411476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20421476687dSEd Tanous [&app](const crow::Request& req, 204322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 204422d268cbSEd Tanous const std::string& systemName) { 20453ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 204645ca1b86SEd Tanous { 204745ca1b86SEd Tanous return; 204845ca1b86SEd Tanous } 204922d268cbSEd Tanous if (systemName != "system") 205022d268cbSEd Tanous { 205122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 205222d268cbSEd Tanous systemName); 205322d268cbSEd Tanous return; 205422d268cbSEd Tanous } 2055b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2056b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2057b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2058b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2059b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2060b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2061b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 20621476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 20631476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2064b7028ebfSSpencer Ku }); 2065b7028ebfSSpencer Ku } 2066b7028ebfSSpencer Ku 2067b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2068b7028ebfSSpencer Ku { 2069b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 207022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2071b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2072002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2073002d39b4SEd Tanous [&app](const crow::Request& req, 207422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 207522d268cbSEd Tanous const std::string& systemName) { 2076c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2077c937d2bfSEd Tanous .canDelegateTop = true, 2078c937d2bfSEd Tanous .canDelegateSkip = true, 2079c937d2bfSEd Tanous }; 2080c937d2bfSEd Tanous query_param::Query delegatedQuery; 2081c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 20823ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2083b7028ebfSSpencer Ku { 2084b7028ebfSSpencer Ku return; 2085b7028ebfSSpencer Ku } 208622d268cbSEd Tanous if (systemName != "system") 208722d268cbSEd Tanous { 208822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 208922d268cbSEd Tanous systemName); 209022d268cbSEd Tanous return; 209122d268cbSEd Tanous } 2092b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2093b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2094b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2095b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2096b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2097b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2098b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 20990fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2100b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2101b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2102b7028ebfSSpencer Ku 2103b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2104b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2105b7028ebfSSpencer Ku { 2106b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2107b7028ebfSSpencer Ku return; 2108b7028ebfSSpencer Ku } 21093648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21103648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21115143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2112b7028ebfSSpencer Ku size_t logCount = 0; 2113b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2114b7028ebfSSpencer Ku // control by skip and top. 2115b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21163648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21173648c8beSEd Tanous logCount)) 2118b7028ebfSSpencer Ku { 2119b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2120b7028ebfSSpencer Ku return; 2121b7028ebfSSpencer Ku } 2122b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2123b7028ebfSSpencer Ku // log count 212426f6976fSEd Tanous if (logEntries.empty()) 2125b7028ebfSSpencer Ku { 2126b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2127b7028ebfSSpencer Ku return; 2128b7028ebfSSpencer Ku } 212926f6976fSEd Tanous if (!logEntries.empty()) 2130b7028ebfSSpencer Ku { 2131b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2132b7028ebfSSpencer Ku { 21336d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21343648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21353648c8beSEd Tanous hostLogEntry); 21366d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2137b7028ebfSSpencer Ku } 2138b7028ebfSSpencer Ku 2139b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21403648c8beSEd Tanous if (skip + top < logCount) 2141b7028ebfSSpencer Ku { 2142b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 21430fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 21443648c8beSEd Tanous std::to_string(skip + top); 2145b7028ebfSSpencer Ku } 2146b7028ebfSSpencer Ku } 2147b7028ebfSSpencer Ku }); 2148b7028ebfSSpencer Ku } 2149b7028ebfSSpencer Ku 2150b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2151b7028ebfSSpencer Ku { 2152b7028ebfSSpencer Ku BMCWEB_ROUTE( 215322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2154b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2155b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 215645ca1b86SEd Tanous [&app](const crow::Request& req, 2157b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 215822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 216045ca1b86SEd Tanous { 216145ca1b86SEd Tanous return; 216245ca1b86SEd Tanous } 216322d268cbSEd Tanous if (systemName != "system") 216422d268cbSEd Tanous { 216522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 216622d268cbSEd Tanous systemName); 216722d268cbSEd Tanous return; 216822d268cbSEd Tanous } 2169b7028ebfSSpencer Ku const std::string& targetID = param; 2170b7028ebfSSpencer Ku 2171b7028ebfSSpencer Ku uint64_t idInt = 0; 2172ca45aa3cSEd Tanous 2173ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2174ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2175ca45aa3cSEd Tanous 2176ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 21779db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 21789db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2179b7028ebfSSpencer Ku { 21809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2181b7028ebfSSpencer Ku return; 2182b7028ebfSSpencer Ku } 2183b7028ebfSSpencer Ku 2184b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2185b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2186b7028ebfSSpencer Ku { 2187b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2188b7028ebfSSpencer Ku return; 2189b7028ebfSSpencer Ku } 2190b7028ebfSSpencer Ku 2191b7028ebfSSpencer Ku size_t logCount = 0; 21923648c8beSEd Tanous size_t top = 1; 2193b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2194b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2195b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2196b7028ebfSSpencer Ku // get that entry 2197002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2198002d39b4SEd Tanous logCount)) 2199b7028ebfSSpencer Ku { 2200b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2201b7028ebfSSpencer Ku return; 2202b7028ebfSSpencer Ku } 2203b7028ebfSSpencer Ku 2204b7028ebfSSpencer Ku if (!logEntries.empty()) 2205b7028ebfSSpencer Ku { 22066d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22076d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22086d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2209b7028ebfSSpencer Ku return; 2210b7028ebfSSpencer Ku } 2211b7028ebfSSpencer Ku 2212b7028ebfSSpencer Ku // Requested ID was not found 22139db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2214b7028ebfSSpencer Ku }); 2215b7028ebfSSpencer Ku } 2216b7028ebfSSpencer Ku 2217fdd26906SClaire Weinan constexpr char const* dumpManagerIface = 2218fdd26906SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll"; 2219dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2220fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2221fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22221da66f75SEd Tanous { 22233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 222445ca1b86SEd Tanous { 222545ca1b86SEd Tanous return; 222645ca1b86SEd Tanous } 22277e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22287e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2229e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22301da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2231e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2232e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2233002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2234e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22351da66f75SEd Tanous "Collection of LogServices for this Manager"; 2236002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2237c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2238fdd26906SClaire Weinan 2239c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2240613dabeaSEd Tanous nlohmann::json::object_t journal; 2241613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2242613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2243c4bf6374SJason M. Bills #endif 2244fdd26906SClaire Weinan 2245fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2246fdd26906SClaire Weinan 2247fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 2248fdd26906SClaire Weinan auto respHandler = 2249fdd26906SClaire Weinan [asyncResp]( 2250fdd26906SClaire Weinan const boost::system::error_code ec, 2251fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2252fdd26906SClaire Weinan if (ec) 2253fdd26906SClaire Weinan { 2254fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2255dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2256fdd26906SClaire Weinan << ec; 2257fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2258fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2259fdd26906SClaire Weinan return; 2260fdd26906SClaire Weinan } 2261fdd26906SClaire Weinan 2262fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2263fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2264fdd26906SClaire Weinan 2265fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2266fdd26906SClaire Weinan { 2267fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2268fdd26906SClaire Weinan { 2269613dabeaSEd Tanous nlohmann::json::object_t member; 2270613dabeaSEd Tanous member["@odata.id"] = 2271613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2272613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2273fdd26906SClaire Weinan } 2274fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2275fdd26906SClaire Weinan { 2276613dabeaSEd Tanous nlohmann::json::object_t member; 2277613dabeaSEd Tanous member["@odata.id"] = 2278613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2279613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2280fdd26906SClaire Weinan } 2281fdd26906SClaire Weinan } 2282fdd26906SClaire Weinan 2283e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2284fdd26906SClaire Weinan logServiceArrayLocal.size(); 2285fdd26906SClaire Weinan }; 2286fdd26906SClaire Weinan 2287fdd26906SClaire Weinan crow::connections::systemBus->async_method_call( 2288fdd26906SClaire Weinan respHandler, "xyz.openbmc_project.ObjectMapper", 2289fdd26906SClaire Weinan "/xyz/openbmc_project/object_mapper", 2290fdd26906SClaire Weinan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 2291fdd26906SClaire Weinan "/xyz/openbmc_project/dump", 0, 2292fdd26906SClaire Weinan std::array<const char*, 1>{dumpManagerIface}); 2293fdd26906SClaire Weinan #endif 2294fdd26906SClaire Weinan } 2295fdd26906SClaire Weinan 2296fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2297fdd26906SClaire Weinan { 2298fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2299fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2300fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2301dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2302e1f26343SJason M. Bills } 2303e1f26343SJason M. Bills 23047e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2305e1f26343SJason M. Bills { 23067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2307ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23087e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 230945ca1b86SEd Tanous [&app](const crow::Request& req, 231045ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23127e860f15SJohn Edward Broadbent { 231345ca1b86SEd Tanous return; 231445ca1b86SEd Tanous } 2315e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2316e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23170f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23180f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2319002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2320002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2321c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "BMC Journal"; 2322e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23237c8c4058STejas Patil 23247c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23252b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2326002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23277c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23287c8c4058STejas Patil redfishDateTimeOffset.second; 23297c8c4058STejas Patil 23301476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23311476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23327e860f15SJohn Edward Broadbent }); 2333e1f26343SJason M. Bills } 2334e1f26343SJason M. Bills 23353a48b3a2SJason M. Bills static int 23363a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2337e1f26343SJason M. Bills sd_journal* journal, 23383a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2339e1f26343SJason M. Bills { 2340e1f26343SJason M. Bills // Get the Log Entry contents 2341e1f26343SJason M. Bills int ret = 0; 2342e1f26343SJason M. Bills 2343a8fe54f0SJason M. Bills std::string message; 2344a8fe54f0SJason M. Bills std::string_view syslogID; 2345a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2346a8fe54f0SJason M. Bills if (ret < 0) 2347a8fe54f0SJason M. Bills { 2348a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2349a8fe54f0SJason M. Bills << strerror(-ret); 2350a8fe54f0SJason M. Bills } 2351a8fe54f0SJason M. Bills if (!syslogID.empty()) 2352a8fe54f0SJason M. Bills { 2353a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2354a8fe54f0SJason M. Bills } 2355a8fe54f0SJason M. Bills 235639e77504SEd Tanous std::string_view msg; 235716428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2358e1f26343SJason M. Bills if (ret < 0) 2359e1f26343SJason M. Bills { 2360e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2361e1f26343SJason M. Bills return 1; 2362e1f26343SJason M. Bills } 2363a8fe54f0SJason M. Bills message += std::string(msg); 2364e1f26343SJason M. Bills 2365e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2366271584abSEd Tanous long int severity = 8; // Default to an invalid priority 236716428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2368e1f26343SJason M. Bills if (ret < 0) 2369e1f26343SJason M. Bills { 2370e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2371e1f26343SJason M. Bills } 2372e1f26343SJason M. Bills 2373e1f26343SJason M. Bills // Get the Created time from the timestamp 237416428a1aSJason M. Bills std::string entryTimeStr; 237516428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2376e1f26343SJason M. Bills { 237716428a1aSJason M. Bills return 1; 2378e1f26343SJason M. Bills } 2379e1f26343SJason M. Bills 2380e1f26343SJason M. Bills // Fill in the log entry with the gathered data 23819c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 238284afc48bSJason M. Bills bmcJournalLogEntryJson["@odata.id"] = 238384afc48bSJason M. Bills "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" + 238484afc48bSJason M. Bills bmcJournalLogEntryID; 238584afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 238684afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 238784afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 238884afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 238984afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2390738c1e61SPatrick Williams : severity <= 4 ? "Warning" 239184afc48bSJason M. Bills : "OK"; 239284afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 239384afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2394e1f26343SJason M. Bills return 0; 2395e1f26343SJason M. Bills } 2396e1f26343SJason M. Bills 23977e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2398e1f26343SJason M. Bills { 23997e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2400ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2401002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2402002d39b4SEd Tanous [&app](const crow::Request& req, 2403002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2404c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2405c937d2bfSEd Tanous .canDelegateTop = true, 2406c937d2bfSEd Tanous .canDelegateSkip = true, 2407c937d2bfSEd Tanous }; 2408c937d2bfSEd Tanous query_param::Query delegatedQuery; 2409c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24103ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2411193ad2faSJason M. Bills { 2412193ad2faSJason M. Bills return; 2413193ad2faSJason M. Bills } 24143648c8beSEd Tanous 24153648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24165143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24173648c8beSEd Tanous 24187e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24197e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2420e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2421e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24220f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24230f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2424e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2425e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2426e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24270fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2428e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2429e1f26343SJason M. Bills 24307e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24317e860f15SJohn Edward Broadbent // unique ID for each entry 2432e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2433e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2434e1f26343SJason M. Bills if (ret < 0) 2435e1f26343SJason M. Bills { 2436002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2437f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2438e1f26343SJason M. Bills return; 2439e1f26343SJason M. Bills } 24400fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 24410fda0f12SGeorge Liu journalTmp, sd_journal_close); 2442e1f26343SJason M. Bills journalTmp = nullptr; 2443b01bf299SEd Tanous uint64_t entryCount = 0; 2444e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2445e85d6b16SJason M. Bills bool firstEntry = true; 2446e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2447e1f26343SJason M. Bills { 2448193ad2faSJason M. Bills entryCount++; 24497e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 24507e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 24513648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2452193ad2faSJason M. Bills { 2453193ad2faSJason M. Bills continue; 2454193ad2faSJason M. Bills } 2455193ad2faSJason M. Bills 245616428a1aSJason M. Bills std::string idStr; 2457e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2458e1f26343SJason M. Bills { 2459e1f26343SJason M. Bills continue; 2460e1f26343SJason M. Bills } 2461e85d6b16SJason M. Bills firstEntry = false; 2462e85d6b16SJason M. Bills 24633a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2464c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2465c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2466e1f26343SJason M. Bills { 2467f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2468e1f26343SJason M. Bills return; 2469e1f26343SJason M. Bills } 24703a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2471e1f26343SJason M. Bills } 2472193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 24733648c8beSEd Tanous if (skip + top < entryCount) 2474193ad2faSJason M. Bills { 2475193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 24760fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 24773648c8beSEd Tanous std::to_string(skip + top); 2478193ad2faSJason M. Bills } 24797e860f15SJohn Edward Broadbent }); 2480e1f26343SJason M. Bills } 2481e1f26343SJason M. Bills 24827e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2483e1f26343SJason M. Bills { 24847e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 24857e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2486ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 24877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 248845ca1b86SEd Tanous [&app](const crow::Request& req, 24897e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 24907e860f15SJohn Edward Broadbent const std::string& entryID) { 24913ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 249245ca1b86SEd Tanous { 249345ca1b86SEd Tanous return; 249445ca1b86SEd Tanous } 2495e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2496e1f26343SJason M. Bills uint64_t ts = 0; 2497271584abSEd Tanous uint64_t index = 0; 24988d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2499e1f26343SJason M. Bills { 250016428a1aSJason M. Bills return; 2501e1f26343SJason M. Bills } 2502e1f26343SJason M. Bills 2503e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2504e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2505e1f26343SJason M. Bills if (ret < 0) 2506e1f26343SJason M. Bills { 2507002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2508f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2509e1f26343SJason M. Bills return; 2510e1f26343SJason M. Bills } 2511002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2512002d39b4SEd Tanous journalTmp, sd_journal_close); 2513e1f26343SJason M. Bills journalTmp = nullptr; 25147e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25157e860f15SJohn Edward Broadbent // index tracking the unique ID 2516af07e3f5SJason M. Bills std::string idStr; 2517af07e3f5SJason M. Bills bool firstEntry = true; 2518e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25192056b6d1SManojkiran Eda if (ret < 0) 25202056b6d1SManojkiran Eda { 25212056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25222056b6d1SManojkiran Eda << strerror(-ret); 25232056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25242056b6d1SManojkiran Eda return; 25252056b6d1SManojkiran Eda } 2526271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2527e1f26343SJason M. Bills { 2528e1f26343SJason M. Bills sd_journal_next(journal.get()); 2529af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2530af07e3f5SJason M. Bills { 2531af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2532af07e3f5SJason M. Bills return; 2533af07e3f5SJason M. Bills } 2534af07e3f5SJason M. Bills firstEntry = false; 2535af07e3f5SJason M. Bills } 2536c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2537af07e3f5SJason M. Bills if (idStr != entryID) 2538c4bf6374SJason M. Bills { 25399db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2540c4bf6374SJason M. Bills return; 2541c4bf6374SJason M. Bills } 2542c4bf6374SJason M. Bills 25433a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2544c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 25453a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2546e1f26343SJason M. Bills { 2547f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2548e1f26343SJason M. Bills return; 2549e1f26343SJason M. Bills } 2550d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 25517e860f15SJohn Edward Broadbent }); 2552c9bb6861Sraviteja-b } 2553c9bb6861Sraviteja-b 2554fdd26906SClaire Weinan inline void 2555fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2556fdd26906SClaire Weinan const std::string& dumpType) 2557c9bb6861Sraviteja-b { 2558fdd26906SClaire Weinan std::string dumpPath; 2559fdd26906SClaire Weinan std::string overWritePolicy; 2560fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2561fdd26906SClaire Weinan 2562fdd26906SClaire Weinan if (dumpType == "BMC") 256345ca1b86SEd Tanous { 2564fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2565fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2566fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2567fdd26906SClaire Weinan } 2568fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2569fdd26906SClaire Weinan { 2570fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2571fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2572fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2573fdd26906SClaire Weinan } 2574fdd26906SClaire Weinan else if (dumpType == "System") 2575fdd26906SClaire Weinan { 2576fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2577fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2578fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2579fdd26906SClaire Weinan } 2580fdd26906SClaire Weinan else 2581fdd26906SClaire Weinan { 2582fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2583fdd26906SClaire Weinan << dumpType; 2584fdd26906SClaire Weinan messages::internalError(asyncResp->res); 258545ca1b86SEd Tanous return; 258645ca1b86SEd Tanous } 2587fdd26906SClaire Weinan 2588fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2589fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2590c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2591fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2592fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2593fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 25947c8c4058STejas Patil 25957c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 25962b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 25970fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 25987c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 25997c8c4058STejas Patil redfishDateTimeOffset.second; 26007c8c4058STejas Patil 2601fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2602002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 2603fdd26906SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 2604fdd26906SClaire Weinan 2605fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2606fdd26906SClaire Weinan { 2607002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26081476687dSEd Tanous ["target"] = 2609fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2610fdd26906SClaire Weinan } 2611c9bb6861Sraviteja-b } 2612c9bb6861Sraviteja-b 2613fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2614fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2615fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 26167e860f15SJohn Edward Broadbent { 26173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 261845ca1b86SEd Tanous { 261945ca1b86SEd Tanous return; 262045ca1b86SEd Tanous } 2621fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2622fdd26906SClaire Weinan } 2623c9bb6861Sraviteja-b 262422d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 262522d268cbSEd Tanous crow::App& app, const crow::Request& req, 262622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 262722d268cbSEd Tanous const std::string& chassisId) 262822d268cbSEd Tanous { 262922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 263022d268cbSEd Tanous { 263122d268cbSEd Tanous return; 263222d268cbSEd Tanous } 263322d268cbSEd Tanous if (chassisId != "system") 263422d268cbSEd Tanous { 263522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 263622d268cbSEd Tanous return; 263722d268cbSEd Tanous } 263822d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 263922d268cbSEd Tanous } 264022d268cbSEd Tanous 2641fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2642fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2643fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2644fdd26906SClaire Weinan { 2645fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2646fdd26906SClaire Weinan { 2647fdd26906SClaire Weinan return; 2648fdd26906SClaire Weinan } 2649fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2650fdd26906SClaire Weinan } 2651fdd26906SClaire Weinan 265222d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 265322d268cbSEd Tanous crow::App& app, const crow::Request& req, 265422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 265522d268cbSEd Tanous const std::string& chassisId) 265622d268cbSEd Tanous { 265722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 265822d268cbSEd Tanous { 265922d268cbSEd Tanous return; 266022d268cbSEd Tanous } 266122d268cbSEd Tanous if (chassisId != "system") 266222d268cbSEd Tanous { 266322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 266422d268cbSEd Tanous return; 266522d268cbSEd Tanous } 266622d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 266722d268cbSEd Tanous } 266822d268cbSEd Tanous 2669fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2670fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2671fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2672fdd26906SClaire Weinan const std::string& dumpId) 2673fdd26906SClaire Weinan { 2674fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2675fdd26906SClaire Weinan { 2676fdd26906SClaire Weinan return; 2677fdd26906SClaire Weinan } 2678fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2679fdd26906SClaire Weinan } 268022d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 268122d268cbSEd Tanous crow::App& app, const crow::Request& req, 268222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 268322d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 268422d268cbSEd Tanous { 268522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 268622d268cbSEd Tanous { 268722d268cbSEd Tanous return; 268822d268cbSEd Tanous } 268922d268cbSEd Tanous if (chassisId != "system") 269022d268cbSEd Tanous { 269122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 269222d268cbSEd Tanous return; 269322d268cbSEd Tanous } 269422d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 269522d268cbSEd Tanous } 2696fdd26906SClaire Weinan 2697fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2698fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2699fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2700fdd26906SClaire Weinan const std::string& dumpId) 2701fdd26906SClaire Weinan { 2702fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2703fdd26906SClaire Weinan { 2704fdd26906SClaire Weinan return; 2705fdd26906SClaire Weinan } 2706fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2707fdd26906SClaire Weinan } 2708fdd26906SClaire Weinan 270922d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 271022d268cbSEd Tanous crow::App& app, const crow::Request& req, 271122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 271222d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 271322d268cbSEd Tanous { 271422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 271522d268cbSEd Tanous { 271622d268cbSEd Tanous return; 271722d268cbSEd Tanous } 271822d268cbSEd Tanous if (chassisId != "system") 271922d268cbSEd Tanous { 272022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 272122d268cbSEd Tanous return; 272222d268cbSEd Tanous } 272322d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 272422d268cbSEd Tanous } 272522d268cbSEd Tanous 2726fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2727fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2728fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2729fdd26906SClaire Weinan { 2730fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2731fdd26906SClaire Weinan { 2732fdd26906SClaire Weinan return; 2733fdd26906SClaire Weinan } 2734fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2735fdd26906SClaire Weinan } 2736fdd26906SClaire Weinan 273722d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 273822d268cbSEd Tanous crow::App& app, const crow::Request& req, 273922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 274022d268cbSEd Tanous const std::string& chassisId) 274122d268cbSEd Tanous { 274222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 274322d268cbSEd Tanous { 274422d268cbSEd Tanous return; 274522d268cbSEd Tanous } 274622d268cbSEd Tanous if (chassisId != "system") 274722d268cbSEd Tanous { 274822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 274922d268cbSEd Tanous return; 275022d268cbSEd Tanous } 275122d268cbSEd Tanous createDump(asyncResp, req, "System"); 275222d268cbSEd Tanous } 275322d268cbSEd Tanous 2754fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2755fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2756fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2757fdd26906SClaire Weinan { 2758fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2759fdd26906SClaire Weinan { 2760fdd26906SClaire Weinan return; 2761fdd26906SClaire Weinan } 2762fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2763fdd26906SClaire Weinan } 2764fdd26906SClaire Weinan 276522d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 276622d268cbSEd Tanous crow::App& app, const crow::Request& req, 276722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 276822d268cbSEd Tanous const std::string& chassisId) 276922d268cbSEd Tanous { 277022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 277122d268cbSEd Tanous { 277222d268cbSEd Tanous return; 277322d268cbSEd Tanous } 277422d268cbSEd Tanous if (chassisId != "system") 277522d268cbSEd Tanous { 277622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 277722d268cbSEd Tanous return; 277822d268cbSEd Tanous } 277922d268cbSEd Tanous clearDump(asyncResp, "System"); 278022d268cbSEd Tanous } 278122d268cbSEd Tanous 2782fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2783fdd26906SClaire Weinan { 2784fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2785fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2786fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2787fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2788fdd26906SClaire Weinan } 2789fdd26906SClaire Weinan 2790fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2791fdd26906SClaire Weinan { 2792fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2793fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2794fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2795fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2796c9bb6861Sraviteja-b } 2797c9bb6861Sraviteja-b 27987e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2799c9bb6861Sraviteja-b { 28007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28017e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2802ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2803fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2804fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2805fdd26906SClaire Weinan 28067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28077e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2808ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2809fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2810fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2811c9bb6861Sraviteja-b } 2812c9bb6861Sraviteja-b 28137e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2814c9bb6861Sraviteja-b { 28150fda0f12SGeorge Liu BMCWEB_ROUTE( 28160fda0f12SGeorge Liu app, 28170fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2818ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28197e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2820fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2821fdd26906SClaire Weinan std::ref(app), "BMC")); 2822a43be80fSAsmitha Karunanithi } 2823a43be80fSAsmitha Karunanithi 28247e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 282580319af1SAsmitha Karunanithi { 28260fda0f12SGeorge Liu BMCWEB_ROUTE( 28270fda0f12SGeorge Liu app, 28280fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2829ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2830fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2831fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 283245ca1b86SEd Tanous } 2833fdd26906SClaire Weinan 2834fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2835fdd26906SClaire Weinan { 2836fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2837fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2838fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2839fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2840fdd26906SClaire Weinan } 2841fdd26906SClaire Weinan 2842fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2843fdd26906SClaire Weinan { 2844fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2845fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2846fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2847fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2848fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2849fdd26906SClaire Weinan } 2850fdd26906SClaire Weinan 2851fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2852fdd26906SClaire Weinan { 2853fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2854fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2855fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2856fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2857fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2858fdd26906SClaire Weinan 2859fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2860fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2861fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2862fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2863fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2864fdd26906SClaire Weinan } 2865fdd26906SClaire Weinan 2866fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2867fdd26906SClaire Weinan { 2868fdd26906SClaire Weinan BMCWEB_ROUTE( 2869fdd26906SClaire Weinan app, 2870fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2871fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2872fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2873fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 28745cb1dd27SAsmitha Karunanithi } 28755cb1dd27SAsmitha Karunanithi 28767e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 28775cb1dd27SAsmitha Karunanithi { 287822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2879ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 28806ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 288122d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 28825cb1dd27SAsmitha Karunanithi } 28835cb1dd27SAsmitha Karunanithi 28847e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 28857e860f15SJohn Edward Broadbent { 288622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2887ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 288822d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 288922d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 289022d268cbSEd Tanous std::ref(app))); 28915cb1dd27SAsmitha Karunanithi } 28925cb1dd27SAsmitha Karunanithi 28937e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 28945cb1dd27SAsmitha Karunanithi { 28957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 289622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2897ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 28986ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 289922d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29008d1b46d7Szhanghch05 29017e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 290222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2903ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29046ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 290522d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29065cb1dd27SAsmitha Karunanithi } 2907c9bb6861Sraviteja-b 29087e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2909c9bb6861Sraviteja-b { 29100fda0f12SGeorge Liu BMCWEB_ROUTE( 29110fda0f12SGeorge Liu app, 291222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2913ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 291422d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 291522d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 291622d268cbSEd Tanous std::ref(app))); 2917a43be80fSAsmitha Karunanithi } 2918a43be80fSAsmitha Karunanithi 29197e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2920a43be80fSAsmitha Karunanithi { 29210fda0f12SGeorge Liu BMCWEB_ROUTE( 29220fda0f12SGeorge Liu app, 292322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2924ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29256ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 292622d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2927013487e5Sraviteja-b } 2928013487e5Sraviteja-b 29297e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29301da66f75SEd Tanous { 29313946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29323946028dSAppaRao Puli // method for security reasons. 29331da66f75SEd Tanous /** 29341da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29351da66f75SEd Tanous */ 293622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2937ed398213SEd Tanous // This is incorrect, should be: 2938ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2939432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2940002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2941002d39b4SEd Tanous [&app](const crow::Request& req, 294222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 294322d268cbSEd Tanous const std::string& systemName) { 29443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 294545ca1b86SEd Tanous { 294645ca1b86SEd Tanous return; 294745ca1b86SEd Tanous } 294822d268cbSEd Tanous if (systemName != "system") 294922d268cbSEd Tanous { 295022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 295122d268cbSEd Tanous systemName); 295222d268cbSEd Tanous return; 295322d268cbSEd Tanous } 295422d268cbSEd Tanous 29557e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29567e860f15SJohn Edward Broadbent // SubRoute 29570f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2958424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 2959e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 29608e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 29614f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 29624f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 29634f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 2964e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 2965e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 29667c8c4058STejas Patil 29677c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 29682b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 29697c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 29707c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 29717c8c4058STejas Patil redfishDateTimeOffset.second; 29727c8c4058STejas Patil 29731476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 29741476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 2975002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 29761476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 2977002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 29781476687dSEd Tanous ["target"] = 29791476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 29807e860f15SJohn Edward Broadbent }); 29811da66f75SEd Tanous } 29821da66f75SEd Tanous 29837e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 29845b61b5e8SJason M. Bills { 29850fda0f12SGeorge Liu BMCWEB_ROUTE( 29860fda0f12SGeorge Liu app, 298722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 2988ed398213SEd Tanous // This is incorrect, should be: 2989ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 2990432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 29917e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 299245ca1b86SEd Tanous [&app](const crow::Request& req, 299322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 299422d268cbSEd Tanous const std::string& systemName) { 29953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 299645ca1b86SEd Tanous { 299745ca1b86SEd Tanous return; 299845ca1b86SEd Tanous } 299922d268cbSEd Tanous if (systemName != "system") 300022d268cbSEd Tanous { 300122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 300222d268cbSEd Tanous systemName); 300322d268cbSEd Tanous return; 300422d268cbSEd Tanous } 30055b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30065b61b5e8SJason M. Bills [asyncResp](const boost::system::error_code ec, 3007cb13a392SEd Tanous const std::string&) { 30085b61b5e8SJason M. Bills if (ec) 30095b61b5e8SJason M. Bills { 30105b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30115b61b5e8SJason M. Bills return; 30125b61b5e8SJason M. Bills } 30135b61b5e8SJason M. Bills messages::success(asyncResp->res); 30145b61b5e8SJason M. Bills }, 3015002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30167e860f15SJohn Edward Broadbent }); 30175b61b5e8SJason M. Bills } 30185b61b5e8SJason M. Bills 30198d1b46d7Szhanghch05 static void 30208d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30218d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3022e855dd28SJason M. Bills { 3023043a0536SJohnathan Mantey auto getStoredLogCallback = 3024b9d36b47SEd Tanous [asyncResp, logID, 3025b9d36b47SEd Tanous &logEntryJson](const boost::system::error_code ec, 3026b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3027e855dd28SJason M. Bills if (ec) 3028e855dd28SJason M. Bills { 3029e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 30301ddcf01aSJason M. Bills if (ec.value() == 30311ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30321ddcf01aSJason M. Bills { 3033002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30341ddcf01aSJason M. Bills } 30351ddcf01aSJason M. Bills else 30361ddcf01aSJason M. Bills { 3037e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30381ddcf01aSJason M. Bills } 3039e855dd28SJason M. Bills return; 3040e855dd28SJason M. Bills } 3041043a0536SJohnathan Mantey 3042043a0536SJohnathan Mantey std::string timestamp{}; 3043043a0536SJohnathan Mantey std::string filename{}; 3044043a0536SJohnathan Mantey std::string logfile{}; 30452c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3046043a0536SJohnathan Mantey 3047043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3048e855dd28SJason M. Bills { 30499db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3050e855dd28SJason M. Bills return; 3051e855dd28SJason M. Bills } 3052e855dd28SJason M. Bills 3053043a0536SJohnathan Mantey std::string crashdumpURI = 3054e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3055043a0536SJohnathan Mantey logID + "/" + filename; 305684afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30579c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 305884afc48bSJason M. Bills logEntry["@odata.id"] = 305984afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID; 306084afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 306184afc48bSJason M. Bills logEntry["Id"] = logID; 306284afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 306384afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 306484afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 306584afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 306684afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 30672b20ef6eSJason M. Bills 30682b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 30692b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 30702b20ef6eSJason M. Bills // directly 30712b20ef6eSJason M. Bills if (logEntryJson.is_array()) 30722b20ef6eSJason M. Bills { 30732b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 30742b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 30752b20ef6eSJason M. Bills logEntryJson.size(); 30762b20ef6eSJason M. Bills } 30772b20ef6eSJason M. Bills else 30782b20ef6eSJason M. Bills { 3079d405bb51SJason M. Bills logEntryJson.update(logEntry); 30802b20ef6eSJason M. Bills } 3081e855dd28SJason M. Bills }; 3082d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3083d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3084d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3085d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3086e855dd28SJason M. Bills } 3087e855dd28SJason M. Bills 30887e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 30891da66f75SEd Tanous { 30903946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30913946028dSAppaRao Puli // method for security reasons. 30921da66f75SEd Tanous /** 30931da66f75SEd Tanous * Functions triggers appropriate requests on DBus 30941da66f75SEd Tanous */ 30957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 309622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3097ed398213SEd Tanous // This is incorrect, should be. 3098ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3099432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3100002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3101002d39b4SEd Tanous [&app](const crow::Request& req, 310222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 310322d268cbSEd Tanous const std::string& systemName) { 31043ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 310545ca1b86SEd Tanous { 310645ca1b86SEd Tanous return; 310745ca1b86SEd Tanous } 310822d268cbSEd Tanous if (systemName != "system") 310922d268cbSEd Tanous { 311022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 311122d268cbSEd Tanous systemName); 311222d268cbSEd Tanous return; 311322d268cbSEd Tanous } 311422d268cbSEd Tanous 31152b20ef6eSJason M. Bills crow::connections::systemBus->async_method_call( 31162b20ef6eSJason M. Bills [asyncResp](const boost::system::error_code ec, 31172b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31181da66f75SEd Tanous if (ec) 31191da66f75SEd Tanous { 31201da66f75SEd Tanous if (ec.value() != 31211da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31221da66f75SEd Tanous { 31231da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 31241da66f75SEd Tanous << ec.message(); 3125f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31261da66f75SEd Tanous return; 31271da66f75SEd Tanous } 31281da66f75SEd Tanous } 3129e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31301da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 31310f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3132424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3133002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3134e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3135424c4176SJason M. Bills "Collection of Crashdump Entries"; 3136002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3137a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31382b20ef6eSJason M. Bills 31392b20ef6eSJason M. Bills for (const std::string& path : resp) 31401da66f75SEd Tanous { 31412b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3142e855dd28SJason M. Bills // Get the log ID 31432b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31442b20ef6eSJason M. Bills if (logID.empty()) 31451da66f75SEd Tanous { 3146e855dd28SJason M. Bills continue; 31471da66f75SEd Tanous } 3148e855dd28SJason M. Bills // Add the log entry to the array 31492b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31502b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31511da66f75SEd Tanous } 31522b20ef6eSJason M. Bills }, 31531da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", 31541da66f75SEd Tanous "/xyz/openbmc_project/object_mapper", 31551da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0, 31565b61b5e8SJason M. Bills std::array<const char*, 1>{crashdumpInterface}); 31577e860f15SJohn Edward Broadbent }); 31581da66f75SEd Tanous } 31591da66f75SEd Tanous 31607e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31611da66f75SEd Tanous { 31623946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31633946028dSAppaRao Puli // method for security reasons. 31641da66f75SEd Tanous 31657e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 316622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3167ed398213SEd Tanous // this is incorrect, should be 3168ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3169432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 31707e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 317145ca1b86SEd Tanous [&app](const crow::Request& req, 31727e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 317322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 31743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 317545ca1b86SEd Tanous { 317645ca1b86SEd Tanous return; 317745ca1b86SEd Tanous } 317822d268cbSEd Tanous if (systemName != "system") 317922d268cbSEd Tanous { 318022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 318122d268cbSEd Tanous systemName); 318222d268cbSEd Tanous ; 318322d268cbSEd Tanous return; 318422d268cbSEd Tanous } 31857e860f15SJohn Edward Broadbent const std::string& logID = param; 3186e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 31877e860f15SJohn Edward Broadbent }); 3188e855dd28SJason M. Bills } 3189e855dd28SJason M. Bills 31907e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3191e855dd28SJason M. Bills { 31923946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31933946028dSAppaRao Puli // method for security reasons. 31947e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 31957e860f15SJohn Edward Broadbent app, 319622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3197ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 31987e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3199a4ce114aSNan Zhou [](const crow::Request& req, 32007e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 320122d268cbSEd Tanous const std::string& systemName, const std::string& logID, 320222d268cbSEd Tanous const std::string& fileName) { 32032a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32042a9beeedSShounak Mitra // Redfish resource. 320522d268cbSEd Tanous 320622d268cbSEd Tanous if (systemName != "system") 320722d268cbSEd Tanous { 320822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 320922d268cbSEd Tanous systemName); 321022d268cbSEd Tanous ; 321122d268cbSEd Tanous return; 321222d268cbSEd Tanous } 321322d268cbSEd Tanous 3214043a0536SJohnathan Mantey auto getStoredLogCallback = 3215002d39b4SEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))]( 3216abf2add6SEd Tanous const boost::system::error_code ec, 3217002d39b4SEd Tanous const std::vector< 3218002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32197e860f15SJohn Edward Broadbent resp) { 32201da66f75SEd Tanous if (ec) 32211da66f75SEd Tanous { 3222002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3223f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32241da66f75SEd Tanous return; 32251da66f75SEd Tanous } 3226e855dd28SJason M. Bills 3227043a0536SJohnathan Mantey std::string dbusFilename{}; 3228043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3229043a0536SJohnathan Mantey std::string dbusFilepath{}; 3230043a0536SJohnathan Mantey 3231002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3232002d39b4SEd Tanous dbusFilepath); 3233043a0536SJohnathan Mantey 3234043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3235043a0536SJohnathan Mantey dbusFilepath.empty()) 32361da66f75SEd Tanous { 32379db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32381da66f75SEd Tanous return; 32391da66f75SEd Tanous } 3240e855dd28SJason M. Bills 3241043a0536SJohnathan Mantey // Verify the file name parameter is correct 3242043a0536SJohnathan Mantey if (fileName != dbusFilename) 3243043a0536SJohnathan Mantey { 32449db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3245043a0536SJohnathan Mantey return; 3246043a0536SJohnathan Mantey } 3247043a0536SJohnathan Mantey 3248043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3249043a0536SJohnathan Mantey { 32509db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3251043a0536SJohnathan Mantey return; 3252043a0536SJohnathan Mantey } 3253002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3254002d39b4SEd Tanous asyncResp->res.body() = 3255002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3256043a0536SJohnathan Mantey 32577e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32587e860f15SJohn Edward Broadbent // from a browser 3259d9f6c621SEd Tanous asyncResp->res.addHeader( 3260d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 32611da66f75SEd Tanous }; 3262d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3263d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3264d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3265d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 32667e860f15SJohn Edward Broadbent }); 32671da66f75SEd Tanous } 32681da66f75SEd Tanous 3269c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3270c5a4c82aSJason M. Bills { 3271c5a4c82aSJason M. Bills onDemand, 3272c5a4c82aSJason M. Bills telemetry, 3273c5a4c82aSJason M. Bills invalid, 3274c5a4c82aSJason M. Bills }; 3275c5a4c82aSJason M. Bills 3276f7725d79SEd Tanous inline OEMDiagnosticType 3277f7725d79SEd Tanous getOEMDiagnosticType(const std::string_view& oemDiagStr) 3278c5a4c82aSJason M. Bills { 3279c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3280c5a4c82aSJason M. Bills { 3281c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3282c5a4c82aSJason M. Bills } 3283c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3284c5a4c82aSJason M. Bills { 3285c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3286c5a4c82aSJason M. Bills } 3287c5a4c82aSJason M. Bills 3288c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3289c5a4c82aSJason M. Bills } 3290c5a4c82aSJason M. Bills 32917e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 32921da66f75SEd Tanous { 32933946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32943946028dSAppaRao Puli // method for security reasons. 32950fda0f12SGeorge Liu BMCWEB_ROUTE( 32960fda0f12SGeorge Liu app, 329722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3298ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3299ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3300432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3301002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3302002d39b4SEd Tanous [&app](const crow::Request& req, 330322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 330422d268cbSEd Tanous const std::string& systemName) { 33053ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 330645ca1b86SEd Tanous { 330745ca1b86SEd Tanous return; 330845ca1b86SEd Tanous } 330922d268cbSEd Tanous 331022d268cbSEd Tanous if (systemName != "system") 331122d268cbSEd Tanous { 331222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 331322d268cbSEd Tanous systemName); 331422d268cbSEd Tanous ; 331522d268cbSEd Tanous return; 331622d268cbSEd Tanous } 331722d268cbSEd Tanous 33188e6c099aSJason M. Bills std::string diagnosticDataType; 33198e6c099aSJason M. Bills std::string oemDiagnosticDataType; 332015ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3321002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3322002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33238e6c099aSJason M. Bills { 33248e6c099aSJason M. Bills return; 33258e6c099aSJason M. Bills } 33268e6c099aSJason M. Bills 33278e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33288e6c099aSJason M. Bills { 33298e6c099aSJason M. Bills BMCWEB_LOG_ERROR 33308e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 33318e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33328e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33338e6c099aSJason M. Bills "CollectDiagnosticData"); 33348e6c099aSJason M. Bills return; 33358e6c099aSJason M. Bills } 33368e6c099aSJason M. Bills 3337c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3338c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3339c5a4c82aSJason M. Bills 3340c5a4c82aSJason M. Bills std::string iface; 3341c5a4c82aSJason M. Bills std::string method; 3342c5a4c82aSJason M. Bills std::string taskMatchStr; 3343c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3344c5a4c82aSJason M. Bills { 3345c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3346c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3347c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3348c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3349c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3350c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3351c5a4c82aSJason M. Bills } 3352c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3353c5a4c82aSJason M. Bills { 3354c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3355c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3356c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3357c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3358c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3359c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3360c5a4c82aSJason M. Bills } 3361c5a4c82aSJason M. Bills else 3362c5a4c82aSJason M. Bills { 3363c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3364c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3365c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3366002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3367002d39b4SEd Tanous "CollectDiagnosticData"); 3368c5a4c82aSJason M. Bills return; 3369c5a4c82aSJason M. Bills } 3370c5a4c82aSJason M. Bills 3371c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3372c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 3373c5a4c82aSJason M. Bills taskMatchStr](const boost::system::error_code ec, 337498be3e39SEd Tanous const std::string&) mutable { 33751da66f75SEd Tanous if (ec) 33761da66f75SEd Tanous { 3377002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 33781da66f75SEd Tanous { 3379f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 33801da66f75SEd Tanous } 33814363d3b2SJason M. Bills else if (ec.value() == 33824363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 33834363d3b2SJason M. Bills { 3384002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3385002d39b4SEd Tanous "60"); 33864363d3b2SJason M. Bills } 33871da66f75SEd Tanous else 33881da66f75SEd Tanous { 3389f12894f8SJason M. Bills messages::internalError(asyncResp->res); 33901da66f75SEd Tanous } 33911da66f75SEd Tanous return; 33921da66f75SEd Tanous } 3393002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 339459d494eeSPatrick Williams [](boost::system::error_code err, sdbusplus::message_t&, 3395002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 339666afe4faSJames Feist if (!err) 339766afe4faSJames Feist { 3398002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3399e5d5006bSJames Feist std::to_string(taskData->index))); 3400831d6b09SJames Feist taskData->state = "Completed"; 340166afe4faSJames Feist } 340232898ceaSJames Feist return task::completed; 340366afe4faSJames Feist }, 3404c5a4c82aSJason M. Bills taskMatchStr); 3405c5a4c82aSJason M. Bills 340646229577SJames Feist task->startTimer(std::chrono::minutes(5)); 340746229577SJames Feist task->populateResp(asyncResp->res); 340898be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34091da66f75SEd Tanous }; 34108e6c099aSJason M. Bills 34111da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3412002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3413002d39b4SEd Tanous iface, method); 34147e860f15SJohn Edward Broadbent }); 34156eda7685SKenny L. Ku } 34166eda7685SKenny L. Ku 3417cb92c03bSAndrew Geissler /** 3418cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3419cb92c03bSAndrew Geissler */ 34207e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3421cb92c03bSAndrew Geissler { 3422cb92c03bSAndrew Geissler /** 3423cb92c03bSAndrew Geissler * Function handles POST method request. 3424cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3425cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3426cb92c03bSAndrew Geissler */ 34277e860f15SJohn Edward Broadbent 34280fda0f12SGeorge Liu BMCWEB_ROUTE( 34290fda0f12SGeorge Liu app, 343022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3431ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34327e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 343345ca1b86SEd Tanous [&app](const crow::Request& req, 343422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 343522d268cbSEd Tanous const std::string& systemName) { 34363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 343745ca1b86SEd Tanous { 343845ca1b86SEd Tanous return; 343945ca1b86SEd Tanous } 344022d268cbSEd Tanous if (systemName != "system") 344122d268cbSEd Tanous { 344222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 344322d268cbSEd Tanous systemName); 344422d268cbSEd Tanous ; 344522d268cbSEd Tanous return; 344622d268cbSEd Tanous } 3447cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3448cb92c03bSAndrew Geissler 3449cb92c03bSAndrew Geissler // Process response from Logging service. 3450002d39b4SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code ec) { 3451002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3452cb92c03bSAndrew Geissler if (ec) 3453cb92c03bSAndrew Geissler { 3454cb92c03bSAndrew Geissler // TODO Handle for specific error code 3455002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3456cb92c03bSAndrew Geissler asyncResp->res.result( 3457cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3458cb92c03bSAndrew Geissler return; 3459cb92c03bSAndrew Geissler } 3460cb92c03bSAndrew Geissler 3461002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3462cb92c03bSAndrew Geissler }; 3463cb92c03bSAndrew Geissler 3464cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3465cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 34662c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3467cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3468cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 34697e860f15SJohn Edward Broadbent }); 3470cb92c03bSAndrew Geissler } 3471a3316fc6SZhikuiRen 3472a3316fc6SZhikuiRen /**************************************************** 3473a3316fc6SZhikuiRen * Redfish PostCode interfaces 3474a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3475a3316fc6SZhikuiRen ******************************************************/ 34767e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3477a3316fc6SZhikuiRen { 347822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3479ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3480002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3481002d39b4SEd Tanous [&app](const crow::Request& req, 348222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 348322d268cbSEd Tanous const std::string& systemName) { 34843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 348545ca1b86SEd Tanous { 348645ca1b86SEd Tanous return; 348745ca1b86SEd Tanous } 348822d268cbSEd Tanous if (systemName != "system") 348922d268cbSEd Tanous { 349022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 349122d268cbSEd Tanous systemName); 349222d268cbSEd Tanous ; 349322d268cbSEd Tanous return; 349422d268cbSEd Tanous } 34951476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 34961476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 34971476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 34981476687dSEd Tanous "#LogService.v1_1_0.LogService"; 34991476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35001476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 35011476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log"; 35021476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35031476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35041476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35057c8c4058STejas Patil 35067c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35072b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35080fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35097c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35107c8c4058STejas Patil redfishDateTimeOffset.second; 35117c8c4058STejas Patil 3512a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 35137e860f15SJohn Edward Broadbent {"target", 35140fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 35157e860f15SJohn Edward Broadbent }); 3516a3316fc6SZhikuiRen } 3517a3316fc6SZhikuiRen 35187e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3519a3316fc6SZhikuiRen { 35200fda0f12SGeorge Liu BMCWEB_ROUTE( 35210fda0f12SGeorge Liu app, 352222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3523ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3524ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3525432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35267e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 352745ca1b86SEd Tanous [&app](const crow::Request& req, 352822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352922d268cbSEd Tanous const std::string& systemName) { 35303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 353145ca1b86SEd Tanous { 353245ca1b86SEd Tanous return; 353345ca1b86SEd Tanous } 353422d268cbSEd Tanous if (systemName != "system") 353522d268cbSEd Tanous { 353622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 353722d268cbSEd Tanous systemName); 353822d268cbSEd Tanous ; 353922d268cbSEd Tanous return; 354022d268cbSEd Tanous } 3541a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3542a3316fc6SZhikuiRen 3543a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3544a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3545a3316fc6SZhikuiRen [asyncResp](const boost::system::error_code ec) { 3546a3316fc6SZhikuiRen if (ec) 3547a3316fc6SZhikuiRen { 3548a3316fc6SZhikuiRen // TODO Handle for specific error code 3549002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 35507e860f15SJohn Edward Broadbent << ec; 3551002d39b4SEd Tanous asyncResp->res.result( 3552002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3553a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3554a3316fc6SZhikuiRen return; 3555a3316fc6SZhikuiRen } 3556a3316fc6SZhikuiRen }, 355715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 355815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3559a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35607e860f15SJohn Edward Broadbent }); 3561a3316fc6SZhikuiRen } 3562a3316fc6SZhikuiRen 3563a3316fc6SZhikuiRen static void fillPostCodeEntry( 35648d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 35656c9a279eSManojkiran Eda const boost::container::flat_map< 35666c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3567a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3568a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3569a3316fc6SZhikuiRen { 3570a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3571fffb8c1fSEd Tanous const registries::Message* message = 3572fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3573a3316fc6SZhikuiRen 3574a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3575a3316fc6SZhikuiRen nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 3576a3316fc6SZhikuiRen 3577a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 35786c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 35796c9a279eSManojkiran Eda code : postcode) 3580a3316fc6SZhikuiRen { 3581a3316fc6SZhikuiRen currentCodeIndex++; 3582a3316fc6SZhikuiRen std::string postcodeEntryID = 3583a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3584a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3585a3316fc6SZhikuiRen 3586a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3587a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3588a3316fc6SZhikuiRen 3589a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3590a3316fc6SZhikuiRen { // already incremented 3591a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3592a3316fc6SZhikuiRen } 3593a3316fc6SZhikuiRen else 3594a3316fc6SZhikuiRen { 3595a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3596a3316fc6SZhikuiRen } 3597a3316fc6SZhikuiRen 3598a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3599a3316fc6SZhikuiRen // not fall between top and skip 3600a3316fc6SZhikuiRen if ((codeIndex == 0) && 3601a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3602a3316fc6SZhikuiRen { 3603a3316fc6SZhikuiRen continue; 3604a3316fc6SZhikuiRen } 3605a3316fc6SZhikuiRen 36064e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3607a3316fc6SZhikuiRen // currentIndex 3608a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3609a3316fc6SZhikuiRen { 3610a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3611a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3612a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3613a3316fc6SZhikuiRen continue; 3614a3316fc6SZhikuiRen } 3615a3316fc6SZhikuiRen 3616a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3617a3316fc6SZhikuiRen // index 3618a3316fc6SZhikuiRen 3619a3316fc6SZhikuiRen // Get the Created time from the timestamp 3620a3316fc6SZhikuiRen std::string entryTimeStr; 36211d8782e7SNan Zhou entryTimeStr = 36222b82937eSEd Tanous redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000); 3623a3316fc6SZhikuiRen 3624a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3625a3316fc6SZhikuiRen std::ostringstream hexCode; 3626a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 36276c9a279eSManojkiran Eda << std::get<0>(code.second); 3628a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3629a3316fc6SZhikuiRen // Set Fixed -Point Notation 3630a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3631a3316fc6SZhikuiRen // Set precision to 4 digits 3632a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3633a3316fc6SZhikuiRen // Add double to stream 3634a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3635a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3636a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3637a3316fc6SZhikuiRen 3638a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3639a3316fc6SZhikuiRen std::string msg; 3640a3316fc6SZhikuiRen if (message != nullptr) 3641a3316fc6SZhikuiRen { 3642a3316fc6SZhikuiRen msg = message->message; 3643a3316fc6SZhikuiRen 3644a3316fc6SZhikuiRen // fill in this post code value 3645a3316fc6SZhikuiRen int i = 0; 3646a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3647a3316fc6SZhikuiRen { 3648a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3649a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3650a3316fc6SZhikuiRen if (argPos != std::string::npos) 3651a3316fc6SZhikuiRen { 3652a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3653a3316fc6SZhikuiRen } 3654a3316fc6SZhikuiRen } 3655a3316fc6SZhikuiRen } 3656a3316fc6SZhikuiRen 3657d4342a92STim Lee // Get Severity template from message registry 3658d4342a92STim Lee std::string severity; 3659d4342a92STim Lee if (message != nullptr) 3660d4342a92STim Lee { 36615f2b84eeSEd Tanous severity = message->messageSeverity; 3662d4342a92STim Lee } 3663d4342a92STim Lee 3664a3316fc6SZhikuiRen // add to AsyncResp 3665a3316fc6SZhikuiRen logEntryArray.push_back({}); 3666a3316fc6SZhikuiRen nlohmann::json& bmcLogEntry = logEntryArray.back(); 36679c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 366884afc48bSJason M. Bills bmcLogEntry["@odata.id"] = 36690fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 367084afc48bSJason M. Bills postcodeEntryID; 367184afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 367284afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 367384afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 367484afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 367584afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 367684afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 367784afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 367884afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3679647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3680647b3cdcSGeorge Liu { 3681647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3682647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3683647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3684647b3cdcSGeorge Liu } 3685a3316fc6SZhikuiRen } 3686a3316fc6SZhikuiRen } 3687a3316fc6SZhikuiRen 36888d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3689a3316fc6SZhikuiRen const uint16_t bootIndex, 3690a3316fc6SZhikuiRen const uint64_t codeIndex) 3691a3316fc6SZhikuiRen { 3692a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 36936c9a279eSManojkiran Eda [aResp, bootIndex, 36946c9a279eSManojkiran Eda codeIndex](const boost::system::error_code ec, 36956c9a279eSManojkiran Eda const boost::container::flat_map< 36966c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36976c9a279eSManojkiran Eda postcode) { 3698a3316fc6SZhikuiRen if (ec) 3699a3316fc6SZhikuiRen { 3700a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3701a3316fc6SZhikuiRen messages::internalError(aResp->res); 3702a3316fc6SZhikuiRen return; 3703a3316fc6SZhikuiRen } 3704a3316fc6SZhikuiRen 3705a3316fc6SZhikuiRen // skip the empty postcode boots 3706a3316fc6SZhikuiRen if (postcode.empty()) 3707a3316fc6SZhikuiRen { 3708a3316fc6SZhikuiRen return; 3709a3316fc6SZhikuiRen } 3710a3316fc6SZhikuiRen 3711a3316fc6SZhikuiRen fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex); 3712a3316fc6SZhikuiRen 3713a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = 3714a3316fc6SZhikuiRen aResp->res.jsonValue["Members"].size(); 3715a3316fc6SZhikuiRen }, 371615124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 371715124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3718a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3719a3316fc6SZhikuiRen bootIndex); 3720a3316fc6SZhikuiRen } 3721a3316fc6SZhikuiRen 37228d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3723a3316fc6SZhikuiRen const uint16_t bootIndex, 3724a3316fc6SZhikuiRen const uint16_t bootCount, 37253648c8beSEd Tanous const uint64_t entryCount, size_t skip, 37263648c8beSEd Tanous size_t top) 3727a3316fc6SZhikuiRen { 3728a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3729a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 3730a3316fc6SZhikuiRen top](const boost::system::error_code ec, 37316c9a279eSManojkiran Eda const boost::container::flat_map< 37326c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37336c9a279eSManojkiran Eda postcode) { 3734a3316fc6SZhikuiRen if (ec) 3735a3316fc6SZhikuiRen { 3736a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3737a3316fc6SZhikuiRen messages::internalError(aResp->res); 3738a3316fc6SZhikuiRen return; 3739a3316fc6SZhikuiRen } 3740a3316fc6SZhikuiRen 3741a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3742a3316fc6SZhikuiRen if (!postcode.empty()) 3743a3316fc6SZhikuiRen { 3744a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 37453648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3746a3316fc6SZhikuiRen { 37473648c8beSEd Tanous uint64_t thisBootSkip = 37483648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 37493648c8beSEd Tanous entryCount; 3750a3316fc6SZhikuiRen uint64_t thisBootTop = 37513648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 37523648c8beSEd Tanous entryCount; 3753a3316fc6SZhikuiRen 3754002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3755002d39b4SEd Tanous thisBootTop); 3756a3316fc6SZhikuiRen } 3757a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3758a3316fc6SZhikuiRen } 3759a3316fc6SZhikuiRen 3760a3316fc6SZhikuiRen // continue to previous bootIndex 3761a3316fc6SZhikuiRen if (bootIndex < bootCount) 3762a3316fc6SZhikuiRen { 3763a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3764a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3765a3316fc6SZhikuiRen } 376681584abeSJiaqing Zhao else if (skip + top < endCount) 3767a3316fc6SZhikuiRen { 3768a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 37690fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3770a3316fc6SZhikuiRen std::to_string(skip + top); 3771a3316fc6SZhikuiRen } 3772a3316fc6SZhikuiRen }, 377315124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 377415124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3775a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3776a3316fc6SZhikuiRen bootIndex); 3777a3316fc6SZhikuiRen } 3778a3316fc6SZhikuiRen 37798d1b46d7Szhanghch05 static void 37808d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 37813648c8beSEd Tanous size_t skip, size_t top) 3782a3316fc6SZhikuiRen { 3783a3316fc6SZhikuiRen uint64_t entryCount = 0; 37841e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 37851e1e598dSJonathan Doman *crow::connections::systemBus, 37861e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 37871e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 37881e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 37891e1e598dSJonathan Doman [aResp, entryCount, skip, top](const boost::system::error_code ec, 37901e1e598dSJonathan Doman const uint16_t bootCount) { 3791a3316fc6SZhikuiRen if (ec) 3792a3316fc6SZhikuiRen { 3793a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3794a3316fc6SZhikuiRen messages::internalError(aResp->res); 3795a3316fc6SZhikuiRen return; 3796a3316fc6SZhikuiRen } 37971e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 37981e1e598dSJonathan Doman }); 3799a3316fc6SZhikuiRen } 3800a3316fc6SZhikuiRen 38017e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3802a3316fc6SZhikuiRen { 38037e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 380422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3805ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 38067e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 380745ca1b86SEd Tanous [&app](const crow::Request& req, 380822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 380922d268cbSEd Tanous const std::string& systemName) { 3810c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3811c937d2bfSEd Tanous .canDelegateTop = true, 3812c937d2bfSEd Tanous .canDelegateSkip = true, 3813c937d2bfSEd Tanous }; 3814c937d2bfSEd Tanous query_param::Query delegatedQuery; 3815c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 38163ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 381745ca1b86SEd Tanous { 381845ca1b86SEd Tanous return; 381945ca1b86SEd Tanous } 382022d268cbSEd Tanous 382122d268cbSEd Tanous if (systemName != "system") 382222d268cbSEd Tanous { 382322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 382422d268cbSEd Tanous systemName); 382522d268cbSEd Tanous ; 382622d268cbSEd Tanous return; 382722d268cbSEd Tanous } 3828a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3829a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3830a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3831a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3832a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3833a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3834a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3835a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3836a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 38373648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 38385143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 38393648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 38407e860f15SJohn Edward Broadbent }); 3841a3316fc6SZhikuiRen } 3842a3316fc6SZhikuiRen 3843647b3cdcSGeorge Liu /** 3844647b3cdcSGeorge Liu * @brief Parse post code ID and get the current value and index value 3845647b3cdcSGeorge Liu * eg: postCodeID=B1-2, currentValue=1, index=2 3846647b3cdcSGeorge Liu * 3847647b3cdcSGeorge Liu * @param[in] postCodeID Post Code ID 3848647b3cdcSGeorge Liu * @param[out] currentValue Current value 3849647b3cdcSGeorge Liu * @param[out] index Index value 3850647b3cdcSGeorge Liu * 3851647b3cdcSGeorge Liu * @return bool true if the parsing is successful, false the parsing fails 3852647b3cdcSGeorge Liu */ 3853647b3cdcSGeorge Liu inline static bool parsePostCode(const std::string& postCodeID, 3854647b3cdcSGeorge Liu uint64_t& currentValue, uint16_t& index) 3855647b3cdcSGeorge Liu { 3856647b3cdcSGeorge Liu std::vector<std::string> split; 3857647b3cdcSGeorge Liu boost::algorithm::split(split, postCodeID, boost::is_any_of("-")); 3858647b3cdcSGeorge Liu if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 3859647b3cdcSGeorge Liu { 3860647b3cdcSGeorge Liu return false; 3861647b3cdcSGeorge Liu } 3862647b3cdcSGeorge Liu 3863ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3864647b3cdcSGeorge Liu const char* start = split[0].data() + 1; 3865ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3866647b3cdcSGeorge Liu const char* end = split[0].data() + split[0].size(); 3867647b3cdcSGeorge Liu auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 3868647b3cdcSGeorge Liu 3869647b3cdcSGeorge Liu if (ptrIndex != end || ecIndex != std::errc()) 3870647b3cdcSGeorge Liu { 3871647b3cdcSGeorge Liu return false; 3872647b3cdcSGeorge Liu } 3873647b3cdcSGeorge Liu 3874647b3cdcSGeorge Liu start = split[1].data(); 3875ca45aa3cSEd Tanous 3876ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3877647b3cdcSGeorge Liu end = split[1].data() + split[1].size(); 3878647b3cdcSGeorge Liu auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 3879647b3cdcSGeorge Liu 3880517d9a58STony Lee return ptrValue == end && ecValue == std::errc(); 3881647b3cdcSGeorge Liu } 3882647b3cdcSGeorge Liu 3883647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3884647b3cdcSGeorge Liu { 38850fda0f12SGeorge Liu BMCWEB_ROUTE( 38860fda0f12SGeorge Liu app, 388722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3888647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3889647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 389045ca1b86SEd Tanous [&app](const crow::Request& req, 3891647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 389222d268cbSEd Tanous const std::string& systemName, 3893647b3cdcSGeorge Liu const std::string& postCodeID) { 38943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 389545ca1b86SEd Tanous { 389645ca1b86SEd Tanous return; 389745ca1b86SEd Tanous } 389899351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 389999351cd8SEd Tanous req.getHeaderValue("Accept"), 39004a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3901647b3cdcSGeorge Liu { 3902002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3903647b3cdcSGeorge Liu return; 3904647b3cdcSGeorge Liu } 390522d268cbSEd Tanous if (systemName != "system") 390622d268cbSEd Tanous { 390722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 390822d268cbSEd Tanous systemName); 390922d268cbSEd Tanous ; 391022d268cbSEd Tanous return; 391122d268cbSEd Tanous } 3912647b3cdcSGeorge Liu 3913647b3cdcSGeorge Liu uint64_t currentValue = 0; 3914647b3cdcSGeorge Liu uint16_t index = 0; 3915647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3916647b3cdcSGeorge Liu { 3917002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3918647b3cdcSGeorge Liu return; 3919647b3cdcSGeorge Liu } 3920647b3cdcSGeorge Liu 3921647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3922647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 3923647b3cdcSGeorge Liu const boost::system::error_code ec, 3924002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 3925002d39b4SEd Tanous postcodes) { 3926647b3cdcSGeorge Liu if (ec.value() == EBADR) 3927647b3cdcSGeorge Liu { 3928002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3929002d39b4SEd Tanous postCodeID); 3930647b3cdcSGeorge Liu return; 3931647b3cdcSGeorge Liu } 3932647b3cdcSGeorge Liu if (ec) 3933647b3cdcSGeorge Liu { 3934647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3935647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 3936647b3cdcSGeorge Liu return; 3937647b3cdcSGeorge Liu } 3938647b3cdcSGeorge Liu 3939647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 3940002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 3941647b3cdcSGeorge Liu { 3942647b3cdcSGeorge Liu BMCWEB_LOG_ERROR << "Wrong currentValue value"; 3943002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3944002d39b4SEd Tanous postCodeID); 3945647b3cdcSGeorge Liu return; 3946647b3cdcSGeorge Liu } 3947647b3cdcSGeorge Liu 39489eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 394946ff87baSEd Tanous if (c.empty()) 3950647b3cdcSGeorge Liu { 3951647b3cdcSGeorge Liu BMCWEB_LOG_INFO << "No found post code data"; 3952002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3953002d39b4SEd Tanous postCodeID); 3954647b3cdcSGeorge Liu return; 3955647b3cdcSGeorge Liu } 395646ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 395746ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 395846ff87baSEd Tanous std::string_view strData(d, c.size()); 3959647b3cdcSGeorge Liu 3960d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 3961647b3cdcSGeorge Liu "application/octet-stream"); 3962d9f6c621SEd Tanous asyncResp->res.addHeader( 3963d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 3964002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 3965647b3cdcSGeorge Liu }, 3966647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 3967647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 3968002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 3969647b3cdcSGeorge Liu }); 3970647b3cdcSGeorge Liu } 3971647b3cdcSGeorge Liu 39727e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 3973a3316fc6SZhikuiRen { 39747e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 397522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 3976ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 39777e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 397845ca1b86SEd Tanous [&app](const crow::Request& req, 39797e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 398022d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 39813ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 398245ca1b86SEd Tanous { 398345ca1b86SEd Tanous return; 398445ca1b86SEd Tanous } 398522d268cbSEd Tanous if (systemName != "system") 398622d268cbSEd Tanous { 398722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 398822d268cbSEd Tanous systemName); 398922d268cbSEd Tanous return; 399022d268cbSEd Tanous } 399122d268cbSEd Tanous 3992647b3cdcSGeorge Liu uint16_t bootIndex = 0; 3993647b3cdcSGeorge Liu uint64_t codeIndex = 0; 3994647b3cdcSGeorge Liu if (!parsePostCode(targetID, codeIndex, bootIndex)) 3995a3316fc6SZhikuiRen { 3996a3316fc6SZhikuiRen // Requested ID was not found 39979db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 3998a3316fc6SZhikuiRen return; 3999a3316fc6SZhikuiRen } 4000a3316fc6SZhikuiRen if (bootIndex == 0 || codeIndex == 0) 4001a3316fc6SZhikuiRen { 4002a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string " 40037e860f15SJohn Edward Broadbent << targetID; 4004a3316fc6SZhikuiRen } 4005a3316fc6SZhikuiRen 40069c11a172SVijay Lobo asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4007a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 40080fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4009a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4010a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4011a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4012a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4013a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 4014a3316fc6SZhikuiRen 4015a3316fc6SZhikuiRen getPostCodeForEntry(asyncResp, bootIndex, codeIndex); 40167e860f15SJohn Edward Broadbent }); 4017a3316fc6SZhikuiRen } 4018a3316fc6SZhikuiRen 40191da66f75SEd Tanous } // namespace redfish 4020