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> 27*8e31778eSAsmitha 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 67*8e31778eSAsmitha Karunanithi enum class DumpCreationProgress 68*8e31778eSAsmitha Karunanithi { 69*8e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 70*8e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 71*8e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 72*8e31778eSAsmitha Karunanithi }; 73*8e31778eSAsmitha 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"; 5105cb1dd27SAsmitha Karunanithi 5115cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5125cb1dd27SAsmitha Karunanithi { 513c6fecdabSClaire Weinan thisEntry["Created"] = redfish::time_utils::getDateTimeUint( 514c6fecdabSClaire Weinan timestampUs / 1000 / 1000); 515d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 516d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 517fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 518fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5195cb1dd27SAsmitha Karunanithi } 520c6fecdabSClaire Weinan else if (dumpType == "FaultLog") 521c6fecdabSClaire Weinan { 522c6fecdabSClaire Weinan thisEntry["Created"] = 523c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 524c6fecdabSClaire Weinan } 5255cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5265cb1dd27SAsmitha Karunanithi { 527c6fecdabSClaire Weinan thisEntry["Created"] = redfish::time_utils::getDateTimeUint( 528c6fecdabSClaire Weinan timestampUs / 1000 / 1000); 529d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 530d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 531d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 532fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 533fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5345cb1dd27SAsmitha Karunanithi } 53535440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5365cb1dd27SAsmitha Karunanithi } 537002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5385cb1dd27SAsmitha Karunanithi }, 5395cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5405cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 5415cb1dd27SAsmitha Karunanithi } 5425cb1dd27SAsmitha Karunanithi 5438d1b46d7Szhanghch05 inline void 544c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5458d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5465cb1dd27SAsmitha Karunanithi { 547fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 548fdd26906SClaire Weinan if (entriesPath.empty()) 5495cb1dd27SAsmitha Karunanithi { 5505cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5515cb1dd27SAsmitha Karunanithi return; 5525cb1dd27SAsmitha Karunanithi } 5535cb1dd27SAsmitha Karunanithi 5545cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 555fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 556fdd26906SClaire Weinan entriesPath](const boost::system::error_code ec, 55702cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5585cb1dd27SAsmitha Karunanithi if (ec) 5595cb1dd27SAsmitha Karunanithi { 5605cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5615cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5625cb1dd27SAsmitha Karunanithi return; 5635cb1dd27SAsmitha Karunanithi } 5645cb1dd27SAsmitha Karunanithi 565b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 566b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 567b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 568002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 569b47452b2SAsmitha Karunanithi 5709eb808c1SEd Tanous for (const auto& objectPath : resp) 5715cb1dd27SAsmitha Karunanithi { 572b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 5735cb1dd27SAsmitha Karunanithi { 5745cb1dd27SAsmitha Karunanithi continue; 5755cb1dd27SAsmitha Karunanithi } 5765cb1dd27SAsmitha Karunanithi 5775cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 578c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5795cb1dd27SAsmitha Karunanithi uint64_t size = 0; 58035440d18SAsmitha Karunanithi std::string dumpStatus; 5815cb1dd27SAsmitha Karunanithi 582aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 583c6fecdabSClaire Weinan timestampUs, asyncResp); 5845cb1dd27SAsmitha Karunanithi 5850fda0f12SGeorge Liu if (dumpStatus != 5860fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 58735440d18SAsmitha Karunanithi !dumpStatus.empty()) 58835440d18SAsmitha Karunanithi { 58935440d18SAsmitha Karunanithi // Dump status is not Complete 59035440d18SAsmitha Karunanithi // return not found until status is changed to Completed 591d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 592d1bde9e5SKrzysztof Grobelny entryID); 59335440d18SAsmitha Karunanithi return; 59435440d18SAsmitha Karunanithi } 59535440d18SAsmitha Karunanithi 5965cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 5979c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 598fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5995cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6005cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6015cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 6025cb1dd27SAsmitha Karunanithi 6035cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6045cb1dd27SAsmitha Karunanithi { 605c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 606c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUint(timestampUs / 1000 / 607c6fecdabSClaire Weinan 1000); 608d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 609d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 610fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 611fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6125cb1dd27SAsmitha Karunanithi } 613c6fecdabSClaire Weinan else if (dumpType == "FaultLog") 614c6fecdabSClaire Weinan { 615c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 616c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 617c6fecdabSClaire Weinan } 6185cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6195cb1dd27SAsmitha Karunanithi { 620c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 621c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUint(timestampUs / 1000 / 622c6fecdabSClaire Weinan 1000); 623d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 624002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 625d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 626fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 627fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6285cb1dd27SAsmitha Karunanithi } 6295cb1dd27SAsmitha Karunanithi } 630e05aec50SEd Tanous if (!foundDumpEntry) 631b47452b2SAsmitha Karunanithi { 632b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 633b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 634b47452b2SAsmitha Karunanithi return; 635b47452b2SAsmitha Karunanithi } 6365cb1dd27SAsmitha Karunanithi }, 6375cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6385cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6395cb1dd27SAsmitha Karunanithi } 6405cb1dd27SAsmitha Karunanithi 6418d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6429878256fSStanley Chu const std::string& entryID, 643b47452b2SAsmitha Karunanithi const std::string& dumpType) 6445cb1dd27SAsmitha Karunanithi { 645002d39b4SEd Tanous auto respHandler = 646002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 6475cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6485cb1dd27SAsmitha Karunanithi if (ec) 6495cb1dd27SAsmitha Karunanithi { 6503de8d8baSGeorge Liu if (ec.value() == EBADR) 6513de8d8baSGeorge Liu { 6523de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6533de8d8baSGeorge Liu return; 6543de8d8baSGeorge Liu } 6555cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 656fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6575cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6585cb1dd27SAsmitha Karunanithi return; 6595cb1dd27SAsmitha Karunanithi } 6605cb1dd27SAsmitha Karunanithi }; 6615cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6625cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 663b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 664b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 665b47452b2SAsmitha Karunanithi entryID, 6665cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 6675cb1dd27SAsmitha Karunanithi } 6685cb1dd27SAsmitha Karunanithi 669*8e31778eSAsmitha Karunanithi inline DumpCreationProgress 670*8e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 671a43be80fSAsmitha Karunanithi { 672*8e31778eSAsmitha Karunanithi if (status == 673*8e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 674*8e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 675*8e31778eSAsmitha Karunanithi { 676*8e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 677*8e31778eSAsmitha Karunanithi } 678*8e31778eSAsmitha Karunanithi if (status == 679*8e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 680*8e31778eSAsmitha Karunanithi { 681*8e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 682*8e31778eSAsmitha Karunanithi } 683*8e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 684*8e31778eSAsmitha Karunanithi } 685*8e31778eSAsmitha Karunanithi 686*8e31778eSAsmitha Karunanithi inline DumpCreationProgress 687*8e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 688*8e31778eSAsmitha Karunanithi { 689*8e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 690*8e31778eSAsmitha Karunanithi { 691*8e31778eSAsmitha Karunanithi if (key == "Status") 692*8e31778eSAsmitha Karunanithi { 693*8e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 694*8e31778eSAsmitha Karunanithi if (value == nullptr) 695*8e31778eSAsmitha Karunanithi { 696*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 697*8e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 698*8e31778eSAsmitha Karunanithi } 699*8e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 700*8e31778eSAsmitha Karunanithi } 701*8e31778eSAsmitha Karunanithi } 702*8e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 703*8e31778eSAsmitha Karunanithi } 704*8e31778eSAsmitha Karunanithi 705*8e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 706*8e31778eSAsmitha Karunanithi { 707*8e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 708*8e31778eSAsmitha Karunanithi { 709*8e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 710*8e31778eSAsmitha Karunanithi } 711*8e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 712*8e31778eSAsmitha Karunanithi { 713*8e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 714*8e31778eSAsmitha Karunanithi } 715*8e31778eSAsmitha Karunanithi return ""; 716*8e31778eSAsmitha Karunanithi } 717*8e31778eSAsmitha Karunanithi 718*8e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 719*8e31778eSAsmitha Karunanithi task::Payload&& payload, 720*8e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 721*8e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 722*8e31778eSAsmitha Karunanithi { 723*8e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 724*8e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 725*8e31778eSAsmitha Karunanithi 726*8e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 727*8e31778eSAsmitha Karunanithi 728*8e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 729*8e31778eSAsmitha Karunanithi { 730*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 731*8e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 732*8e31778eSAsmitha Karunanithi return; 733*8e31778eSAsmitha Karunanithi } 734*8e31778eSAsmitha Karunanithi 735*8e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 736*8e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 737*8e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 738*8e31778eSAsmitha Karunanithi dumpId](const boost::system::error_code ec, 739*8e31778eSAsmitha Karunanithi const std::string& introspectXml) { 740*8e31778eSAsmitha Karunanithi if (ec) 741*8e31778eSAsmitha Karunanithi { 742*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 743*8e31778eSAsmitha Karunanithi << ec.message(); 744*8e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 745*8e31778eSAsmitha Karunanithi return; 746*8e31778eSAsmitha Karunanithi } 747*8e31778eSAsmitha Karunanithi 748*8e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 749*8e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 750*8e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 751*8e31778eSAsmitha Karunanithi // Else, return task completed. 752*8e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 753*8e31778eSAsmitha Karunanithi 754*8e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 755*8e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 756*8e31778eSAsmitha Karunanithi if (pRoot == nullptr) 757*8e31778eSAsmitha Karunanithi { 758*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 759*8e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 760*8e31778eSAsmitha Karunanithi return; 761*8e31778eSAsmitha Karunanithi } 762*8e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 763*8e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 764*8e31778eSAsmitha Karunanithi 765*8e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 766*8e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 767*8e31778eSAsmitha Karunanithi { 768*8e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 769*8e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 770*8e31778eSAsmitha Karunanithi { 771*8e31778eSAsmitha Karunanithi if (thisInterfaceName == 772*8e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 773*8e31778eSAsmitha Karunanithi { 774*8e31778eSAsmitha Karunanithi interfaceNode = 775*8e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 776*8e31778eSAsmitha Karunanithi continue; 777*8e31778eSAsmitha Karunanithi } 778*8e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 779*8e31778eSAsmitha Karunanithi break; 780*8e31778eSAsmitha Karunanithi } 781*8e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 782*8e31778eSAsmitha Karunanithi } 783*8e31778eSAsmitha Karunanithi 784a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 785*8e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 786*8e31778eSAsmitha Karunanithi boost::system::error_code err, sdbusplus::message::message& msg, 787a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 788cb13a392SEd Tanous if (err) 789cb13a392SEd Tanous { 790*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 791*8e31778eSAsmitha Karunanithi << ": Error in creating dump"; 792*8e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 7936145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 7946145ed6fSAsmitha Karunanithi return task::completed; 795cb13a392SEd Tanous } 796b9d36b47SEd Tanous 797*8e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 798a43be80fSAsmitha Karunanithi { 799*8e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 800*8e31778eSAsmitha Karunanithi std::string prop; 801*8e31778eSAsmitha Karunanithi msg.read(prop, values); 802*8e31778eSAsmitha Karunanithi 803*8e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 804*8e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 805*8e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 806*8e31778eSAsmitha Karunanithi { 807*8e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 808*8e31778eSAsmitha Karunanithi << ": Error in creating dump"; 809*8e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 810*8e31778eSAsmitha Karunanithi return task::completed; 811*8e31778eSAsmitha Karunanithi } 812*8e31778eSAsmitha Karunanithi 813*8e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 814*8e31778eSAsmitha Karunanithi { 815*8e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 816*8e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 817*8e31778eSAsmitha Karunanithi return !task::completed; 818*8e31778eSAsmitha Karunanithi } 819*8e31778eSAsmitha Karunanithi } 820*8e31778eSAsmitha Karunanithi 821a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 822a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 823a43be80fSAsmitha Karunanithi 824a43be80fSAsmitha Karunanithi std::string headerLoc = 825*8e31778eSAsmitha Karunanithi "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId); 826002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 827a43be80fSAsmitha Karunanithi 828*8e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 829*8e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 830a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 831b47452b2SAsmitha Karunanithi return task::completed; 832a43be80fSAsmitha Karunanithi }, 833*8e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 834*8e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 835*8e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 836a43be80fSAsmitha Karunanithi 837*8e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 838*8e31778eSAsmitha Karunanithi // requested dump will be collected. 839*8e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 840a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 841*8e31778eSAsmitha Karunanithi task->payload.emplace(payload); 842*8e31778eSAsmitha Karunanithi }, 843*8e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 844*8e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 845a43be80fSAsmitha Karunanithi } 846a43be80fSAsmitha Karunanithi 8478d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8488d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 849a43be80fSAsmitha Karunanithi { 850fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 851fdd26906SClaire Weinan if (dumpPath.empty()) 852a43be80fSAsmitha Karunanithi { 853a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 854a43be80fSAsmitha Karunanithi return; 855a43be80fSAsmitha Karunanithi } 856a43be80fSAsmitha Karunanithi 857a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 858a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 859a43be80fSAsmitha Karunanithi 86015ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 861a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 862a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 863a43be80fSAsmitha Karunanithi { 864a43be80fSAsmitha Karunanithi return; 865a43be80fSAsmitha Karunanithi } 866a43be80fSAsmitha Karunanithi 867a43be80fSAsmitha Karunanithi if (dumpType == "System") 868a43be80fSAsmitha Karunanithi { 869a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 870a43be80fSAsmitha Karunanithi { 8714978b63fSJason M. Bills BMCWEB_LOG_ERROR 8724978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 873a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 874a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 875a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 876a43be80fSAsmitha Karunanithi return; 877a43be80fSAsmitha Karunanithi } 8783174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 879a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 880a43be80fSAsmitha Karunanithi { 881a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 882ace85d60SEd Tanous messages::internalError(asyncResp->res); 883a43be80fSAsmitha Karunanithi return; 884a43be80fSAsmitha Karunanithi } 8855907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 886a43be80fSAsmitha Karunanithi } 887a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 888a43be80fSAsmitha Karunanithi { 889a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 890a43be80fSAsmitha Karunanithi { 8910fda0f12SGeorge Liu BMCWEB_LOG_ERROR 8920fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 893a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 894a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 895a43be80fSAsmitha Karunanithi return; 896a43be80fSAsmitha Karunanithi } 8973174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 898a43be80fSAsmitha Karunanithi { 899a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 900a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 901ace85d60SEd Tanous messages::internalError(asyncResp->res); 902a43be80fSAsmitha Karunanithi return; 903a43be80fSAsmitha Karunanithi } 9045907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 9055907571dSAsmitha Karunanithi } 9065907571dSAsmitha Karunanithi else 9075907571dSAsmitha Karunanithi { 9085907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 9095907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9105907571dSAsmitha Karunanithi return; 911a43be80fSAsmitha Karunanithi } 912a43be80fSAsmitha Karunanithi 913*8e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 914*8e31778eSAsmitha Karunanithi createDumpParamVec; 915*8e31778eSAsmitha Karunanithi 916a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 917*8e31778eSAsmitha Karunanithi [asyncResp, payload(task::Payload(req)), 918*8e31778eSAsmitha Karunanithi dumpPath](const boost::system::error_code ec, 9195907571dSAsmitha Karunanithi const sdbusplus::message::message& msg, 920*8e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 921a43be80fSAsmitha Karunanithi if (ec) 922a43be80fSAsmitha Karunanithi { 923a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9245907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9255907571dSAsmitha Karunanithi if (dbusError == nullptr) 9265907571dSAsmitha Karunanithi { 9275907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9285907571dSAsmitha Karunanithi return; 9295907571dSAsmitha Karunanithi } 9305907571dSAsmitha Karunanithi 9315907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9325907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9335907571dSAsmitha Karunanithi if (std::string_view( 9345907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9355907571dSAsmitha Karunanithi dbusError->name) 9365907571dSAsmitha Karunanithi { 9375907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9385907571dSAsmitha Karunanithi return; 9395907571dSAsmitha Karunanithi } 9405907571dSAsmitha Karunanithi if (std::string_view( 9415907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9425907571dSAsmitha Karunanithi dbusError->name) 9435907571dSAsmitha Karunanithi { 9445907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9455907571dSAsmitha Karunanithi return; 9465907571dSAsmitha Karunanithi } 9475907571dSAsmitha Karunanithi if (std::string_view( 9485907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9495907571dSAsmitha Karunanithi dbusError->name) 9505907571dSAsmitha Karunanithi { 9515907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 9525907571dSAsmitha Karunanithi return; 9535907571dSAsmitha Karunanithi } 9545907571dSAsmitha Karunanithi // Other Dbus errors such as: 9555907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 9565907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 9575907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 9585907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 9595907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 9605907571dSAsmitha Karunanithi // back to the client. 961a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 962a43be80fSAsmitha Karunanithi return; 963a43be80fSAsmitha Karunanithi } 964*8e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 965*8e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 966a43be80fSAsmitha Karunanithi }, 967b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 968b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 969b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 970*8e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 971a43be80fSAsmitha Karunanithi } 972a43be80fSAsmitha Karunanithi 9738d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9748d1b46d7Szhanghch05 const std::string& dumpType) 97580319af1SAsmitha Karunanithi { 976b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 977b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 9788d1b46d7Szhanghch05 97980319af1SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 980b9d36b47SEd Tanous [asyncResp, dumpType]( 981b9d36b47SEd Tanous const boost::system::error_code ec, 982b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 98380319af1SAsmitha Karunanithi if (ec) 98480319af1SAsmitha Karunanithi { 98580319af1SAsmitha Karunanithi BMCWEB_LOG_ERROR << "resp_handler got error " << ec; 98680319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 98780319af1SAsmitha Karunanithi return; 98880319af1SAsmitha Karunanithi } 98980319af1SAsmitha Karunanithi 99080319af1SAsmitha Karunanithi for (const std::string& path : subTreePaths) 99180319af1SAsmitha Karunanithi { 9922dfd18efSEd Tanous sdbusplus::message::object_path objPath(path); 9932dfd18efSEd Tanous std::string logID = objPath.filename(); 9942dfd18efSEd Tanous if (logID.empty()) 99580319af1SAsmitha Karunanithi { 9962dfd18efSEd Tanous continue; 99780319af1SAsmitha Karunanithi } 9982dfd18efSEd Tanous deleteDumpEntry(asyncResp, logID, dumpType); 99980319af1SAsmitha Karunanithi } 100080319af1SAsmitha Karunanithi }, 100180319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", 100280319af1SAsmitha Karunanithi "/xyz/openbmc_project/object_mapper", 100380319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 1004b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, 1005b47452b2SAsmitha Karunanithi std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." + 1006b47452b2SAsmitha Karunanithi dumpType}); 100780319af1SAsmitha Karunanithi } 100880319af1SAsmitha Karunanithi 1009b9d36b47SEd Tanous inline static void 1010b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1011b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1012b9d36b47SEd Tanous std::string& logfile) 1013043a0536SJohnathan Mantey { 1014d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1015d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1016d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1017d1bde9e5SKrzysztof Grobelny 1018d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1019d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1020d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1021d1bde9e5SKrzysztof Grobelny 1022d1bde9e5SKrzysztof Grobelny if (!success) 1023043a0536SJohnathan Mantey { 1024d1bde9e5SKrzysztof Grobelny return; 1025043a0536SJohnathan Mantey } 1026d1bde9e5SKrzysztof Grobelny 1027d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1028043a0536SJohnathan Mantey { 1029d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1030d1bde9e5SKrzysztof Grobelny } 1031d1bde9e5SKrzysztof Grobelny 1032d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1033043a0536SJohnathan Mantey { 1034d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1035043a0536SJohnathan Mantey } 1036d1bde9e5SKrzysztof Grobelny 1037d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1038043a0536SJohnathan Mantey { 1039d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1040043a0536SJohnathan Mantey } 1041043a0536SJohnathan Mantey } 1042043a0536SJohnathan Mantey 1043a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode"; 10447e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10451da66f75SEd Tanous { 1046c4bf6374SJason M. Bills /** 1047c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1048c4bf6374SJason M. Bills */ 104922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1050ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1051002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1052002d39b4SEd Tanous [&app](const crow::Request& req, 105322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 105422d268cbSEd Tanous const std::string& systemName) { 10553ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1056c4bf6374SJason M. Bills { 105745ca1b86SEd Tanous return; 105845ca1b86SEd Tanous } 105922d268cbSEd Tanous if (systemName != "system") 106022d268cbSEd Tanous { 106122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 106222d268cbSEd Tanous systemName); 106322d268cbSEd Tanous return; 106422d268cbSEd Tanous } 106522d268cbSEd Tanous 10667e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10677e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1068c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1069c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1070c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1071029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 107245ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1073c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1074c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1075002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1076c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 10771476687dSEd Tanous nlohmann::json::object_t eventLog; 10781476687dSEd Tanous eventLog["@odata.id"] = 10791476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 10801476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 10815cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 10821476687dSEd Tanous nlohmann::json::object_t dumpLog; 1083002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 10841476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 1085c9bb6861Sraviteja-b #endif 1086c9bb6861Sraviteja-b 1087d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 10881476687dSEd Tanous nlohmann::json::object_t crashdump; 10891476687dSEd Tanous crashdump["@odata.id"] = 10901476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 10911476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 1092d53dd41fSJason M. Bills #endif 1093b7028ebfSSpencer Ku 1094b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 10951476687dSEd Tanous nlohmann::json::object_t hostlogger; 10961476687dSEd Tanous hostlogger["@odata.id"] = 10971476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 10981476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 1099b7028ebfSSpencer Ku #endif 1100c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1101c4bf6374SJason M. Bills logServiceArray.size(); 1102a3316fc6SZhikuiRen 1103a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 110445ca1b86SEd Tanous [asyncResp](const boost::system::error_code ec, 1105b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1106b9d36b47SEd Tanous subtreePath) { 1107a3316fc6SZhikuiRen if (ec) 1108a3316fc6SZhikuiRen { 1109a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 1110a3316fc6SZhikuiRen return; 1111a3316fc6SZhikuiRen } 1112a3316fc6SZhikuiRen 111355f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1114a3316fc6SZhikuiRen { 1115a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1116a3316fc6SZhikuiRen { 111723a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1118a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1119613dabeaSEd Tanous nlohmann::json::object_t member; 1120613dabeaSEd Tanous member["@odata.id"] = 1121613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1122613dabeaSEd Tanous 1123613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 1124613dabeaSEd Tanous 112545ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 112623a21a1cSEd Tanous logServiceArrayLocal.size(); 1127a3316fc6SZhikuiRen return; 1128a3316fc6SZhikuiRen } 1129a3316fc6SZhikuiRen } 1130a3316fc6SZhikuiRen }, 1131a3316fc6SZhikuiRen "xyz.openbmc_project.ObjectMapper", 1132a3316fc6SZhikuiRen "/xyz/openbmc_project/object_mapper", 113345ca1b86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0, 113445ca1b86SEd Tanous std::array<const char*, 1>{postCodeIface}); 11357e860f15SJohn Edward Broadbent }); 1136c4bf6374SJason M. Bills } 1137c4bf6374SJason M. Bills 11387e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1139c4bf6374SJason M. Bills { 114022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1141ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1142002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1143002d39b4SEd Tanous [&app](const crow::Request& req, 114422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 114522d268cbSEd Tanous const std::string& systemName) { 11463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114745ca1b86SEd Tanous { 114845ca1b86SEd Tanous return; 114945ca1b86SEd Tanous } 115022d268cbSEd Tanous if (systemName != "system") 115122d268cbSEd Tanous { 115222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 115322d268cbSEd Tanous systemName); 115422d268cbSEd Tanous return; 115522d268cbSEd Tanous } 1156c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1157029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1158c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1159c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1160c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1161002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1162c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1163c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11647c8c4058STejas Patil 11657c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11662b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11677c8c4058STejas Patil 11687c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 11697c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 11707c8c4058STejas Patil redfishDateTimeOffset.second; 11717c8c4058STejas Patil 11721476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 11731476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1174e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1175e7d6c8b2SGunnar Mills 11760fda0f12SGeorge Liu {"target", 11770fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 11787e860f15SJohn Edward Broadbent }); 1179489640c6SJason M. Bills } 1180489640c6SJason M. Bills 11817e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1182489640c6SJason M. Bills { 11834978b63fSJason M. Bills BMCWEB_ROUTE( 11844978b63fSJason M. Bills app, 118522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1186432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 11877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 118845ca1b86SEd Tanous [&app](const crow::Request& req, 118922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 119022d268cbSEd Tanous const std::string& systemName) { 11913ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 119245ca1b86SEd Tanous { 119345ca1b86SEd Tanous return; 119445ca1b86SEd Tanous } 119522d268cbSEd Tanous if (systemName != "system") 119622d268cbSEd Tanous { 119722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 119822d268cbSEd Tanous systemName); 119922d268cbSEd Tanous return; 120022d268cbSEd Tanous } 1201489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1202489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1203489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1204489640c6SJason M. Bills { 1205489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1206489640c6SJason M. Bills { 1207489640c6SJason M. Bills std::error_code ec; 1208489640c6SJason M. Bills std::filesystem::remove(file, ec); 1209489640c6SJason M. Bills } 1210489640c6SJason M. Bills } 1211489640c6SJason M. Bills 1212489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1213489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 1214489640c6SJason M. Bills [asyncResp](const boost::system::error_code ec) { 1215489640c6SJason M. Bills if (ec) 1216489640c6SJason M. Bills { 1217002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1218489640c6SJason M. Bills messages::internalError(asyncResp->res); 1219489640c6SJason M. Bills return; 1220489640c6SJason M. Bills } 1221489640c6SJason M. Bills 1222489640c6SJason M. Bills messages::success(asyncResp->res); 1223489640c6SJason M. Bills }, 1224489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1225002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1226002d39b4SEd Tanous "replace"); 12277e860f15SJohn Edward Broadbent }); 1228c4bf6374SJason M. Bills } 1229c4bf6374SJason M. Bills 1230ac992cdeSJason M. Bills enum class LogParseError 1231ac992cdeSJason M. Bills { 1232ac992cdeSJason M. Bills success, 1233ac992cdeSJason M. Bills parseFailed, 1234ac992cdeSJason M. Bills messageIdNotInRegistry, 1235ac992cdeSJason M. Bills }; 1236ac992cdeSJason M. Bills 1237ac992cdeSJason M. Bills static LogParseError 1238ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1239b5a76932SEd Tanous const std::string& logEntry, 1240de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1241c4bf6374SJason M. Bills { 124295820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1243cd225da8SJason M. Bills // First get the Timestamp 1244f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1245cd225da8SJason M. Bills if (space == std::string::npos) 124695820184SJason M. Bills { 1247ac992cdeSJason M. Bills return LogParseError::parseFailed; 124895820184SJason M. Bills } 1249cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1250cd225da8SJason M. Bills // Then get the log contents 1251f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1252cd225da8SJason M. Bills if (entryStart == std::string::npos) 1253cd225da8SJason M. Bills { 1254ac992cdeSJason M. Bills return LogParseError::parseFailed; 1255cd225da8SJason M. Bills } 1256cd225da8SJason M. Bills std::string_view entry(logEntry); 1257cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1258cd225da8SJason M. Bills // Use split to separate the entry into its fields 1259cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 1260cd225da8SJason M. Bills boost::split(logEntryFields, entry, boost::is_any_of(","), 1261cd225da8SJason M. Bills boost::token_compress_on); 1262cd225da8SJason M. Bills // We need at least a MessageId to be valid 126326f6976fSEd Tanous if (logEntryFields.empty()) 1264cd225da8SJason M. Bills { 1265ac992cdeSJason M. Bills return LogParseError::parseFailed; 1266cd225da8SJason M. Bills } 1267cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 126895820184SJason M. Bills 12694851d45dSJason M. Bills // Get the Message from the MessageRegistry 1270fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1271c4bf6374SJason M. Bills 127254417b02SSui Chen if (message == nullptr) 1273c4bf6374SJason M. Bills { 127454417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1275ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1276c4bf6374SJason M. Bills } 1277c4bf6374SJason M. Bills 127854417b02SSui Chen std::string msg = message->message; 127954417b02SSui Chen 128015a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 128126702d01SEd Tanous std::span<std::string> messageArgs; 128215a86ff6SJason M. Bills if (logEntryFields.size() > 1) 128315a86ff6SJason M. Bills { 128415a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 128515a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 128615a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 128715a86ff6SJason M. Bills if (!messageArgsStart.empty()) 128815a86ff6SJason M. Bills { 128915a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 129015a86ff6SJason M. Bills } 129115a86ff6SJason M. Bills 129223a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1293c4bf6374SJason M. Bills 12944851d45dSJason M. Bills // Fill the MessageArgs into the Message 129595820184SJason M. Bills int i = 0; 129695820184SJason M. Bills for (const std::string& messageArg : messageArgs) 12974851d45dSJason M. Bills { 129895820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 12994851d45dSJason M. Bills size_t argPos = msg.find(argStr); 13004851d45dSJason M. Bills if (argPos != std::string::npos) 13014851d45dSJason M. Bills { 130295820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 13034851d45dSJason M. Bills } 13044851d45dSJason M. Bills } 130515a86ff6SJason M. Bills } 13064851d45dSJason M. Bills 130795820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 130895820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 130995820184SJason M. Bills // between the '.' and the '+', so just remove them. 1310f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1311f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 131295820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1313c4bf6374SJason M. Bills { 131495820184SJason M. Bills timestamp.erase(dot, plus - dot); 1315c4bf6374SJason M. Bills } 1316c4bf6374SJason M. Bills 1317c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13189c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 131984afc48bSJason M. Bills logEntryJson["@odata.id"] = 132084afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID; 132184afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 132284afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 132384afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 132484afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 132584afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 132684afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 132784afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 132884afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1329ac992cdeSJason M. Bills return LogParseError::success; 1330c4bf6374SJason M. Bills } 1331c4bf6374SJason M. Bills 13327e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1333c4bf6374SJason M. Bills { 133422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13358b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1336002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1337002d39b4SEd Tanous [&app](const crow::Request& req, 133822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 133922d268cbSEd Tanous const std::string& systemName) { 1340c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1341c937d2bfSEd Tanous .canDelegateTop = true, 1342c937d2bfSEd Tanous .canDelegateSkip = true, 1343c937d2bfSEd Tanous }; 1344c937d2bfSEd Tanous query_param::Query delegatedQuery; 1345c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13463ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1347c4bf6374SJason M. Bills { 1348c4bf6374SJason M. Bills return; 1349c4bf6374SJason M. Bills } 135022d268cbSEd Tanous if (systemName != "system") 135122d268cbSEd Tanous { 135222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 135322d268cbSEd Tanous systemName); 135422d268cbSEd Tanous return; 135522d268cbSEd Tanous } 135622d268cbSEd Tanous 13575143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13583648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13593648c8beSEd Tanous 13607e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13617e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1362c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1363c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1364c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1365029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1366c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1367c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1368c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1369cb92c03bSAndrew Geissler 13704978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1371c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13727e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13737e860f15SJohn Edward Broadbent // entry 137495820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 137595820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1376b01bf299SEd Tanous uint64_t entryCount = 0; 1377cd225da8SJason M. Bills std::string logEntry; 137895820184SJason M. Bills 13797e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13807e860f15SJohn Edward Broadbent // backwards 1381002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1382002d39b4SEd Tanous it++) 1383c4bf6374SJason M. Bills { 1384cd225da8SJason M. Bills std::ifstream logStream(*it); 138595820184SJason M. Bills if (!logStream.is_open()) 1386c4bf6374SJason M. Bills { 1387c4bf6374SJason M. Bills continue; 1388c4bf6374SJason M. Bills } 1389c4bf6374SJason M. Bills 1390e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1391e85d6b16SJason M. Bills bool firstEntry = true; 139295820184SJason M. Bills while (std::getline(logStream, logEntry)) 139395820184SJason M. Bills { 1394c4bf6374SJason M. Bills std::string idStr; 1395e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1396c4bf6374SJason M. Bills { 1397c4bf6374SJason M. Bills continue; 1398c4bf6374SJason M. Bills } 1399e85d6b16SJason M. Bills firstEntry = false; 1400e85d6b16SJason M. Bills 1401de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1402ac992cdeSJason M. Bills LogParseError status = 1403ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1404ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1405ac992cdeSJason M. Bills { 1406ac992cdeSJason M. Bills continue; 1407ac992cdeSJason M. Bills } 1408ac992cdeSJason M. Bills if (status != LogParseError::success) 1409c4bf6374SJason M. Bills { 1410c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1411c4bf6374SJason M. Bills return; 1412c4bf6374SJason M. Bills } 1413de703c5dSJason M. Bills 1414de703c5dSJason M. Bills entryCount++; 1415de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1416de703c5dSJason M. Bills // start) and top (number of entries to display) 14173648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1418de703c5dSJason M. Bills { 1419de703c5dSJason M. Bills continue; 1420de703c5dSJason M. Bills } 1421de703c5dSJason M. Bills 1422de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1423c4bf6374SJason M. Bills } 142495820184SJason M. Bills } 1425c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14263648c8beSEd Tanous if (skip + top < entryCount) 1427c4bf6374SJason M. Bills { 1428c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14294978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14303648c8beSEd Tanous std::to_string(skip + top); 1431c4bf6374SJason M. Bills } 14327e860f15SJohn Edward Broadbent }); 1433897967deSJason M. Bills } 1434897967deSJason M. Bills 14357e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1436897967deSJason M. Bills { 14377e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 143822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1439ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14407e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 144145ca1b86SEd Tanous [&app](const crow::Request& req, 14427e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 144322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 144545ca1b86SEd Tanous { 144645ca1b86SEd Tanous return; 144745ca1b86SEd Tanous } 144822d268cbSEd Tanous 144922d268cbSEd Tanous if (systemName != "system") 145022d268cbSEd Tanous { 145122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 145222d268cbSEd Tanous systemName); 145322d268cbSEd Tanous return; 145422d268cbSEd Tanous } 145522d268cbSEd Tanous 14567e860f15SJohn Edward Broadbent const std::string& targetID = param; 14578d1b46d7Szhanghch05 14587e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14597e860f15SJohn Edward Broadbent // entry to find the target entry 1460897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1461897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1462897967deSJason M. Bills std::string logEntry; 1463897967deSJason M. Bills 14647e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14657e860f15SJohn Edward Broadbent // backwards 1466002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1467002d39b4SEd Tanous it++) 1468897967deSJason M. Bills { 1469897967deSJason M. Bills std::ifstream logStream(*it); 1470897967deSJason M. Bills if (!logStream.is_open()) 1471897967deSJason M. Bills { 1472897967deSJason M. Bills continue; 1473897967deSJason M. Bills } 1474897967deSJason M. Bills 1475897967deSJason M. Bills // Reset the unique ID on the first entry 1476897967deSJason M. Bills bool firstEntry = true; 1477897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1478897967deSJason M. Bills { 1479897967deSJason M. Bills std::string idStr; 1480897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1481897967deSJason M. Bills { 1482897967deSJason M. Bills continue; 1483897967deSJason M. Bills } 1484897967deSJason M. Bills firstEntry = false; 1485897967deSJason M. Bills 1486897967deSJason M. Bills if (idStr == targetID) 1487897967deSJason M. Bills { 1488de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1489ac992cdeSJason M. Bills LogParseError status = 1490ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1491ac992cdeSJason M. Bills if (status != LogParseError::success) 1492897967deSJason M. Bills { 1493897967deSJason M. Bills messages::internalError(asyncResp->res); 1494897967deSJason M. Bills return; 1495897967deSJason M. Bills } 1496d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1497897967deSJason M. Bills return; 1498897967deSJason M. Bills } 1499897967deSJason M. Bills } 1500897967deSJason M. Bills } 1501897967deSJason M. Bills // Requested ID was not found 15029db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15037e860f15SJohn Edward Broadbent }); 150408a4e4b5SAnthony Wilson } 150508a4e4b5SAnthony Wilson 15067e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 150708a4e4b5SAnthony Wilson { 150822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1509ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1510002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1511002d39b4SEd Tanous [&app](const crow::Request& req, 151222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 151322d268cbSEd Tanous const std::string& systemName) { 15143ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 151545ca1b86SEd Tanous { 151645ca1b86SEd Tanous return; 151745ca1b86SEd Tanous } 151822d268cbSEd Tanous if (systemName != "system") 151922d268cbSEd Tanous { 152022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 152122d268cbSEd Tanous systemName); 152222d268cbSEd Tanous return; 152322d268cbSEd Tanous } 152422d268cbSEd Tanous 15257e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15267e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 152708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 152808a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 152908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 153008a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 153108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 153208a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 153308a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 153408a4e4b5SAnthony Wilson 1535cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1536cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1537cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 1538cb92c03bSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1539914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1540cb92c03bSAndrew Geissler if (ec) 1541cb92c03bSAndrew Geissler { 1542cb92c03bSAndrew Geissler // TODO Handle for specific error code 1543cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1544002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1545cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1546cb92c03bSAndrew Geissler return; 1547cb92c03bSAndrew Geissler } 1548002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1549cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15509eb808c1SEd Tanous for (const auto& objectPath : resp) 1551cb92c03bSAndrew Geissler { 1552914e2d5dSEd Tanous const uint32_t* id = nullptr; 1553c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1554c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1555914e2d5dSEd Tanous const std::string* severity = nullptr; 1556914e2d5dSEd Tanous const std::string* message = nullptr; 1557914e2d5dSEd Tanous const std::string* filePath = nullptr; 15589c11a172SVijay Lobo const std::string* resolution = nullptr; 155975710de2SXiaochao Ma bool resolved = false; 15609eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1561f86bb901SAdriana Kobylak { 1562f86bb901SAdriana Kobylak if (interfaceMap.first == 1563f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1564f86bb901SAdriana Kobylak { 1565002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1566cb92c03bSAndrew Geissler { 1567cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1568cb92c03bSAndrew Geissler { 1569002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1570cb92c03bSAndrew Geissler } 1571cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1572cb92c03bSAndrew Geissler { 1573002d39b4SEd Tanous timestamp = 1574002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15757e860f15SJohn Edward Broadbent } 1576002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 15777e860f15SJohn Edward Broadbent { 1578002d39b4SEd Tanous updateTimestamp = 1579002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15807e860f15SJohn Edward Broadbent } 15817e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 15827e860f15SJohn Edward Broadbent { 15837e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 15847e860f15SJohn Edward Broadbent &propertyMap.second); 15857e860f15SJohn Edward Broadbent } 15869c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 15879c11a172SVijay Lobo { 15889c11a172SVijay Lobo resolution = std::get_if<std::string>( 15899c11a172SVijay Lobo &propertyMap.second); 15909c11a172SVijay Lobo } 15917e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 15927e860f15SJohn Edward Broadbent { 15937e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 15947e860f15SJohn Edward Broadbent &propertyMap.second); 15957e860f15SJohn Edward Broadbent } 15967e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 15977e860f15SJohn Edward Broadbent { 1598914e2d5dSEd Tanous const bool* resolveptr = 1599002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16007e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16017e860f15SJohn Edward Broadbent { 1602002d39b4SEd Tanous messages::internalError(asyncResp->res); 16037e860f15SJohn Edward Broadbent return; 16047e860f15SJohn Edward Broadbent } 16057e860f15SJohn Edward Broadbent resolved = *resolveptr; 16067e860f15SJohn Edward Broadbent } 16077e860f15SJohn Edward Broadbent } 16087e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16097e860f15SJohn Edward Broadbent severity == nullptr) 16107e860f15SJohn Edward Broadbent { 16117e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16127e860f15SJohn Edward Broadbent return; 16137e860f15SJohn Edward Broadbent } 16147e860f15SJohn Edward Broadbent } 16157e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16167e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16177e860f15SJohn Edward Broadbent { 1618002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16197e860f15SJohn Edward Broadbent { 16207e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16217e860f15SJohn Edward Broadbent { 16227e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16237e860f15SJohn Edward Broadbent &propertyMap.second); 16247e860f15SJohn Edward Broadbent } 16257e860f15SJohn Edward Broadbent } 16267e860f15SJohn Edward Broadbent } 16277e860f15SJohn Edward Broadbent } 16287e860f15SJohn Edward Broadbent // Object path without the 16297e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16307e860f15SJohn Edward Broadbent // and continue. 16317e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1632c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1633c419c759SEd Tanous updateTimestamp == nullptr) 16347e860f15SJohn Edward Broadbent { 16357e860f15SJohn Edward Broadbent continue; 16367e860f15SJohn Edward Broadbent } 16377e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16387e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16399c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 16407e860f15SJohn Edward Broadbent thisEntry["@odata.id"] = 16410fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16427e860f15SJohn Edward Broadbent std::to_string(*id); 16437e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16447e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16457e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16467e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16479c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16489c11a172SVijay Lobo { 16499c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16509c11a172SVijay Lobo } 16517e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16527e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16537e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16547e860f15SJohn Edward Broadbent thisEntry["Created"] = 16552b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 16567e860f15SJohn Edward Broadbent thisEntry["Modified"] = 16572b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 16587e860f15SJohn Edward Broadbent if (filePath != nullptr) 16597e860f15SJohn Edward Broadbent { 16607e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 16610fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16627e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 16637e860f15SJohn Edward Broadbent } 16647e860f15SJohn Edward Broadbent } 1665002d39b4SEd Tanous std::sort( 1666002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1667002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 16687e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 16697e860f15SJohn Edward Broadbent }); 16707e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 16717e860f15SJohn Edward Broadbent entriesArray.size(); 16727e860f15SJohn Edward Broadbent }, 16737e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 16747e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 16757e860f15SJohn Edward Broadbent }); 16767e860f15SJohn Edward Broadbent } 16777e860f15SJohn Edward Broadbent 16787e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 16797e860f15SJohn Edward Broadbent { 16807e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 168122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1682ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1683002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1684002d39b4SEd Tanous [&app](const crow::Request& req, 16857e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 168622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16873ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 16887e860f15SJohn Edward Broadbent { 168945ca1b86SEd Tanous return; 169045ca1b86SEd Tanous } 169122d268cbSEd Tanous if (systemName != "system") 169222d268cbSEd Tanous { 169322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 169422d268cbSEd Tanous systemName); 169522d268cbSEd Tanous return; 169622d268cbSEd Tanous } 169722d268cbSEd Tanous 16987e860f15SJohn Edward Broadbent std::string entryID = param; 16997e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17007e860f15SJohn Edward Broadbent 17017e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17027e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1703d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1704d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1705d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 1706002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1707b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17087e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17097e860f15SJohn Edward Broadbent { 1710d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1711d1bde9e5SKrzysztof Grobelny entryID); 17127e860f15SJohn Edward Broadbent return; 17137e860f15SJohn Edward Broadbent } 17147e860f15SJohn Edward Broadbent if (ec) 17157e860f15SJohn Edward Broadbent { 17160fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1717002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17187e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17197e860f15SJohn Edward Broadbent return; 17207e860f15SJohn Edward Broadbent } 1721914e2d5dSEd Tanous const uint32_t* id = nullptr; 1722c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1723c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1724914e2d5dSEd Tanous const std::string* severity = nullptr; 1725914e2d5dSEd Tanous const std::string* message = nullptr; 1726914e2d5dSEd Tanous const std::string* filePath = nullptr; 17279c11a172SVijay Lobo const std::string* resolution = nullptr; 17287e860f15SJohn Edward Broadbent bool resolved = false; 17297e860f15SJohn Edward Broadbent 1730d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1731d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1732d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17339c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 17349c11a172SVijay Lobo "Resolution", resolution, "Path", filePath); 1735d1bde9e5SKrzysztof Grobelny 1736d1bde9e5SKrzysztof Grobelny if (!success) 173775710de2SXiaochao Ma { 173875710de2SXiaochao Ma messages::internalError(asyncResp->res); 173975710de2SXiaochao Ma return; 174075710de2SXiaochao Ma } 1741d1bde9e5SKrzysztof Grobelny 1742002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 1743002d39b4SEd Tanous timestamp == nullptr || updateTimestamp == nullptr) 1744f86bb901SAdriana Kobylak { 1745ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1746271584abSEd Tanous return; 1747271584abSEd Tanous } 1748f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17499c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1750f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 17510fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1752f86bb901SAdriana Kobylak std::to_string(*id); 175345ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1754f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1755f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1756f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 17579c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17589c11a172SVijay Lobo { 17599c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 17609c11a172SVijay Lobo } 1761f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1762f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1763f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1764f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 17652b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1766f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 17672b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1768f86bb901SAdriana Kobylak if (filePath != nullptr) 1769f86bb901SAdriana Kobylak { 1770f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1771e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1772e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1773f86bb901SAdriana Kobylak } 1774d1bde9e5SKrzysztof Grobelny }); 17757e860f15SJohn Edward Broadbent }); 1776336e96c6SChicago Duan 17777e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 177822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1779ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 17807e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 178145ca1b86SEd Tanous [&app](const crow::Request& req, 17827e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 178322d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 17843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 178545ca1b86SEd Tanous { 178645ca1b86SEd Tanous return; 178745ca1b86SEd Tanous } 178822d268cbSEd Tanous if (systemName != "system") 178922d268cbSEd Tanous { 179022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 179122d268cbSEd Tanous systemName); 179222d268cbSEd Tanous return; 179322d268cbSEd Tanous } 179475710de2SXiaochao Ma std::optional<bool> resolved; 179575710de2SXiaochao Ma 179615ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 17977e860f15SJohn Edward Broadbent resolved)) 179875710de2SXiaochao Ma { 179975710de2SXiaochao Ma return; 180075710de2SXiaochao Ma } 180175710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 180275710de2SXiaochao Ma 180375710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 18044f48d5f6SEd Tanous [asyncResp, entryId](const boost::system::error_code ec) { 180575710de2SXiaochao Ma if (ec) 180675710de2SXiaochao Ma { 180775710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 180875710de2SXiaochao Ma messages::internalError(asyncResp->res); 180975710de2SXiaochao Ma return; 181075710de2SXiaochao Ma } 181175710de2SXiaochao Ma }, 181275710de2SXiaochao Ma "xyz.openbmc_project.Logging", 181375710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 181475710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 181575710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1816168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18177e860f15SJohn Edward Broadbent }); 181875710de2SXiaochao Ma 18197e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 182022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1821ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1822ed398213SEd Tanous 1823002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1824002d39b4SEd Tanous [&app](const crow::Request& req, 1825002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 182622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1828336e96c6SChicago Duan { 182945ca1b86SEd Tanous return; 183045ca1b86SEd Tanous } 183122d268cbSEd Tanous if (systemName != "system") 183222d268cbSEd Tanous { 183322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 183422d268cbSEd Tanous systemName); 183522d268cbSEd Tanous return; 183622d268cbSEd Tanous } 1837336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1838336e96c6SChicago Duan 18397e860f15SJohn Edward Broadbent std::string entryID = param; 1840336e96c6SChicago Duan 1841336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1842336e96c6SChicago Duan 1843336e96c6SChicago Duan // Process response from Logging service. 1844002d39b4SEd Tanous auto respHandler = 1845002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 1846002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1847336e96c6SChicago Duan if (ec) 1848336e96c6SChicago Duan { 18493de8d8baSGeorge Liu if (ec.value() == EBADR) 18503de8d8baSGeorge Liu { 185145ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 185245ca1b86SEd Tanous entryID); 18533de8d8baSGeorge Liu return; 18543de8d8baSGeorge Liu } 1855336e96c6SChicago Duan // TODO Handle for specific error code 18560fda0f12SGeorge Liu BMCWEB_LOG_ERROR 18570fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1858336e96c6SChicago Duan << ec; 1859336e96c6SChicago Duan asyncResp->res.result( 1860336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1861336e96c6SChicago Duan return; 1862336e96c6SChicago Duan } 1863336e96c6SChicago Duan 1864336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1865336e96c6SChicago Duan }; 1866336e96c6SChicago Duan 1867336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1868336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1869336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1870336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1871336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 18727e860f15SJohn Edward Broadbent }); 1873400fd1fbSAdriana Kobylak } 1874400fd1fbSAdriana Kobylak 18757e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1876400fd1fbSAdriana Kobylak { 18770fda0f12SGeorge Liu BMCWEB_ROUTE( 18780fda0f12SGeorge Liu app, 187922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1880ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 18817e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 188245ca1b86SEd Tanous [&app](const crow::Request& req, 18837e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 188422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18853ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 18867e860f15SJohn Edward Broadbent { 188745ca1b86SEd Tanous return; 188845ca1b86SEd Tanous } 188999351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 189099351cd8SEd Tanous req.getHeaderValue("Accept"), 18914a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1892400fd1fbSAdriana Kobylak { 1893002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1894400fd1fbSAdriana Kobylak return; 1895400fd1fbSAdriana Kobylak } 189622d268cbSEd Tanous if (systemName != "system") 189722d268cbSEd Tanous { 189822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 189922d268cbSEd Tanous systemName); 190022d268cbSEd Tanous return; 190122d268cbSEd Tanous } 1902400fd1fbSAdriana Kobylak 19037e860f15SJohn Edward Broadbent std::string entryID = param; 1904400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1905400fd1fbSAdriana Kobylak 1906400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 1907002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1908400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1909400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1910400fd1fbSAdriana Kobylak { 1911002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1912002d39b4SEd Tanous entryID); 1913400fd1fbSAdriana Kobylak return; 1914400fd1fbSAdriana Kobylak } 1915400fd1fbSAdriana Kobylak if (ec) 1916400fd1fbSAdriana Kobylak { 1917400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1918400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1919400fd1fbSAdriana Kobylak return; 1920400fd1fbSAdriana Kobylak } 1921400fd1fbSAdriana Kobylak 1922400fd1fbSAdriana Kobylak int fd = -1; 1923400fd1fbSAdriana Kobylak fd = dup(unixfd); 1924400fd1fbSAdriana Kobylak if (fd == -1) 1925400fd1fbSAdriana Kobylak { 1926400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1927400fd1fbSAdriana Kobylak return; 1928400fd1fbSAdriana Kobylak } 1929400fd1fbSAdriana Kobylak 1930400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1931400fd1fbSAdriana Kobylak if (size == -1) 1932400fd1fbSAdriana Kobylak { 1933400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1934400fd1fbSAdriana Kobylak return; 1935400fd1fbSAdriana Kobylak } 1936400fd1fbSAdriana Kobylak 1937400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1938400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1939400fd1fbSAdriana Kobylak if (size > maxFileSize) 1940400fd1fbSAdriana Kobylak { 1941002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1942400fd1fbSAdriana Kobylak << maxFileSize; 1943400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1944400fd1fbSAdriana Kobylak return; 1945400fd1fbSAdriana Kobylak } 1946400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1947400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1948400fd1fbSAdriana Kobylak if (rc == -1) 1949400fd1fbSAdriana Kobylak { 1950400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1951400fd1fbSAdriana Kobylak return; 1952400fd1fbSAdriana Kobylak } 1953400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1954400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1955400fd1fbSAdriana Kobylak { 1956400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1957400fd1fbSAdriana Kobylak return; 1958400fd1fbSAdriana Kobylak } 1959400fd1fbSAdriana Kobylak close(fd); 1960400fd1fbSAdriana Kobylak 1961400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 1962002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 1963400fd1fbSAdriana Kobylak 1964d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 1965400fd1fbSAdriana Kobylak "application/octet-stream"); 1966d9f6c621SEd Tanous asyncResp->res.addHeader( 1967d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 1968400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 1969400fd1fbSAdriana Kobylak }, 1970400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 1971400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 1972400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 19737e860f15SJohn Edward Broadbent }); 19741da66f75SEd Tanous } 19751da66f75SEd Tanous 1976b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 1977b7028ebfSSpencer Ku 1978b7028ebfSSpencer Ku inline bool 1979b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 1980b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 1981b7028ebfSSpencer Ku { 1982b7028ebfSSpencer Ku std::error_code ec; 1983b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 1984b7028ebfSSpencer Ku if (ec) 1985b7028ebfSSpencer Ku { 1986b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 1987b7028ebfSSpencer Ku return false; 1988b7028ebfSSpencer Ku } 1989b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 1990b7028ebfSSpencer Ku { 1991b7028ebfSSpencer Ku std::string filename = it.path().filename(); 1992b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 1993b7028ebfSSpencer Ku // path 199411ba3979SEd Tanous if (filename.starts_with("log")) 1995b7028ebfSSpencer Ku { 1996b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 1997b7028ebfSSpencer Ku } 1998b7028ebfSSpencer Ku } 1999b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2000b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2001b7028ebfSSpencer Ku // descending order. 2002b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2003b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2004b7028ebfSSpencer Ku 2005b7028ebfSSpencer Ku return true; 2006b7028ebfSSpencer Ku } 2007b7028ebfSSpencer Ku 200802cad96eSEd Tanous inline bool getHostLoggerEntries( 200902cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 201002cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2011b7028ebfSSpencer Ku { 2012b7028ebfSSpencer Ku GzFileReader logFile; 2013b7028ebfSSpencer Ku 2014b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2015b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2016b7028ebfSSpencer Ku { 2017b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2018b7028ebfSSpencer Ku { 2019b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2020b7028ebfSSpencer Ku return false; 2021b7028ebfSSpencer Ku } 2022b7028ebfSSpencer Ku } 2023b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2024b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2025b7028ebfSSpencer Ku if (!lastMessage.empty()) 2026b7028ebfSSpencer Ku { 2027b7028ebfSSpencer Ku logCount++; 2028b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2029b7028ebfSSpencer Ku { 2030b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2031b7028ebfSSpencer Ku } 2032b7028ebfSSpencer Ku } 2033b7028ebfSSpencer Ku return true; 2034b7028ebfSSpencer Ku } 2035b7028ebfSSpencer Ku 2036b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2037b7028ebfSSpencer Ku const std::string& msg, 20386d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2039b7028ebfSSpencer Ku { 2040b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20419c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 20426d6574c9SJason M. Bills logEntryJson["@odata.id"] = 2043b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" + 20446d6574c9SJason M. Bills logEntryID; 20456d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20466d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20476d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20486d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20496d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20506d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2051b7028ebfSSpencer Ku } 2052b7028ebfSSpencer Ku 2053b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2054b7028ebfSSpencer Ku { 205522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2056b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20571476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20581476687dSEd Tanous [&app](const crow::Request& req, 205922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 206022d268cbSEd Tanous const std::string& systemName) { 20613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 206245ca1b86SEd Tanous { 206345ca1b86SEd Tanous return; 206445ca1b86SEd Tanous } 206522d268cbSEd Tanous if (systemName != "system") 206622d268cbSEd Tanous { 206722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 206822d268cbSEd Tanous systemName); 206922d268cbSEd Tanous return; 207022d268cbSEd Tanous } 2071b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2072b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2073b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2074b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2075b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2076b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2077b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 20781476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 20791476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2080b7028ebfSSpencer Ku }); 2081b7028ebfSSpencer Ku } 2082b7028ebfSSpencer Ku 2083b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2084b7028ebfSSpencer Ku { 2085b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 208622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2087b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2088002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2089002d39b4SEd Tanous [&app](const crow::Request& req, 209022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 209122d268cbSEd Tanous const std::string& systemName) { 2092c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2093c937d2bfSEd Tanous .canDelegateTop = true, 2094c937d2bfSEd Tanous .canDelegateSkip = true, 2095c937d2bfSEd Tanous }; 2096c937d2bfSEd Tanous query_param::Query delegatedQuery; 2097c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 20983ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2099b7028ebfSSpencer Ku { 2100b7028ebfSSpencer Ku return; 2101b7028ebfSSpencer Ku } 210222d268cbSEd Tanous if (systemName != "system") 210322d268cbSEd Tanous { 210422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 210522d268cbSEd Tanous systemName); 210622d268cbSEd Tanous return; 210722d268cbSEd Tanous } 2108b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2109b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2110b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2111b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2112b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2113b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2114b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21150fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2116b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2117b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2118b7028ebfSSpencer Ku 2119b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2120b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2121b7028ebfSSpencer Ku { 2122b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2123b7028ebfSSpencer Ku return; 2124b7028ebfSSpencer Ku } 21253648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21263648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21275143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2128b7028ebfSSpencer Ku size_t logCount = 0; 2129b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2130b7028ebfSSpencer Ku // control by skip and top. 2131b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21323648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21333648c8beSEd Tanous logCount)) 2134b7028ebfSSpencer Ku { 2135b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2136b7028ebfSSpencer Ku return; 2137b7028ebfSSpencer Ku } 2138b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2139b7028ebfSSpencer Ku // log count 214026f6976fSEd Tanous if (logEntries.empty()) 2141b7028ebfSSpencer Ku { 2142b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2143b7028ebfSSpencer Ku return; 2144b7028ebfSSpencer Ku } 214526f6976fSEd Tanous if (!logEntries.empty()) 2146b7028ebfSSpencer Ku { 2147b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2148b7028ebfSSpencer Ku { 21496d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21503648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21513648c8beSEd Tanous hostLogEntry); 21526d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2153b7028ebfSSpencer Ku } 2154b7028ebfSSpencer Ku 2155b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21563648c8beSEd Tanous if (skip + top < logCount) 2157b7028ebfSSpencer Ku { 2158b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 21590fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 21603648c8beSEd Tanous std::to_string(skip + top); 2161b7028ebfSSpencer Ku } 2162b7028ebfSSpencer Ku } 2163b7028ebfSSpencer Ku }); 2164b7028ebfSSpencer Ku } 2165b7028ebfSSpencer Ku 2166b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2167b7028ebfSSpencer Ku { 2168b7028ebfSSpencer Ku BMCWEB_ROUTE( 216922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2170b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2171b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 217245ca1b86SEd Tanous [&app](const crow::Request& req, 2173b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 217422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21753ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 217645ca1b86SEd Tanous { 217745ca1b86SEd Tanous return; 217845ca1b86SEd Tanous } 217922d268cbSEd Tanous if (systemName != "system") 218022d268cbSEd Tanous { 218122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 218222d268cbSEd Tanous systemName); 218322d268cbSEd Tanous return; 218422d268cbSEd Tanous } 2185b7028ebfSSpencer Ku const std::string& targetID = param; 2186b7028ebfSSpencer Ku 2187b7028ebfSSpencer Ku uint64_t idInt = 0; 2188ca45aa3cSEd Tanous 2189ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2190ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2191ca45aa3cSEd Tanous 2192ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 21939db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 21949db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2195b7028ebfSSpencer Ku { 21969db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2197b7028ebfSSpencer Ku return; 2198b7028ebfSSpencer Ku } 2199b7028ebfSSpencer Ku 2200b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2201b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2202b7028ebfSSpencer Ku { 2203b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2204b7028ebfSSpencer Ku return; 2205b7028ebfSSpencer Ku } 2206b7028ebfSSpencer Ku 2207b7028ebfSSpencer Ku size_t logCount = 0; 22083648c8beSEd Tanous size_t top = 1; 2209b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2210b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2211b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2212b7028ebfSSpencer Ku // get that entry 2213002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2214002d39b4SEd Tanous logCount)) 2215b7028ebfSSpencer Ku { 2216b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2217b7028ebfSSpencer Ku return; 2218b7028ebfSSpencer Ku } 2219b7028ebfSSpencer Ku 2220b7028ebfSSpencer Ku if (!logEntries.empty()) 2221b7028ebfSSpencer Ku { 22226d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22236d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22246d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2225b7028ebfSSpencer Ku return; 2226b7028ebfSSpencer Ku } 2227b7028ebfSSpencer Ku 2228b7028ebfSSpencer Ku // Requested ID was not found 22299db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2230b7028ebfSSpencer Ku }); 2231b7028ebfSSpencer Ku } 2232b7028ebfSSpencer Ku 2233fdd26906SClaire Weinan constexpr char const* dumpManagerIface = 2234fdd26906SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll"; 2235dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2236fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2237fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22381da66f75SEd Tanous { 22393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 224045ca1b86SEd Tanous { 224145ca1b86SEd Tanous return; 224245ca1b86SEd Tanous } 22437e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22447e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2245e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22461da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2247e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2248e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2249002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2250e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22511da66f75SEd Tanous "Collection of LogServices for this Manager"; 2252002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2253c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2254fdd26906SClaire Weinan 2255c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2256613dabeaSEd Tanous nlohmann::json::object_t journal; 2257613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2258613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2259c4bf6374SJason M. Bills #endif 2260fdd26906SClaire Weinan 2261fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2262fdd26906SClaire Weinan 2263fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 2264fdd26906SClaire Weinan auto respHandler = 2265fdd26906SClaire Weinan [asyncResp]( 2266fdd26906SClaire Weinan const boost::system::error_code ec, 2267fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2268fdd26906SClaire Weinan if (ec) 2269fdd26906SClaire Weinan { 2270fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2271dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2272fdd26906SClaire Weinan << ec; 2273fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2274fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2275fdd26906SClaire Weinan return; 2276fdd26906SClaire Weinan } 2277fdd26906SClaire Weinan 2278fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2279fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2280fdd26906SClaire Weinan 2281fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2282fdd26906SClaire Weinan { 2283fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2284fdd26906SClaire Weinan { 2285613dabeaSEd Tanous nlohmann::json::object_t member; 2286613dabeaSEd Tanous member["@odata.id"] = 2287613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2288613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2289fdd26906SClaire Weinan } 2290fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2291fdd26906SClaire Weinan { 2292613dabeaSEd Tanous nlohmann::json::object_t member; 2293613dabeaSEd Tanous member["@odata.id"] = 2294613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2295613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2296fdd26906SClaire Weinan } 2297fdd26906SClaire Weinan } 2298fdd26906SClaire Weinan 2299e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2300fdd26906SClaire Weinan logServiceArrayLocal.size(); 2301fdd26906SClaire Weinan }; 2302fdd26906SClaire Weinan 2303fdd26906SClaire Weinan crow::connections::systemBus->async_method_call( 2304fdd26906SClaire Weinan respHandler, "xyz.openbmc_project.ObjectMapper", 2305fdd26906SClaire Weinan "/xyz/openbmc_project/object_mapper", 2306fdd26906SClaire Weinan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 2307fdd26906SClaire Weinan "/xyz/openbmc_project/dump", 0, 2308fdd26906SClaire Weinan std::array<const char*, 1>{dumpManagerIface}); 2309fdd26906SClaire Weinan #endif 2310fdd26906SClaire Weinan } 2311fdd26906SClaire Weinan 2312fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2313fdd26906SClaire Weinan { 2314fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2315fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2316fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2317dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2318e1f26343SJason M. Bills } 2319e1f26343SJason M. Bills 23207e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2321e1f26343SJason M. Bills { 23227e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2323ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23247e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 232545ca1b86SEd Tanous [&app](const crow::Request& req, 232645ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23287e860f15SJohn Edward Broadbent { 232945ca1b86SEd Tanous return; 233045ca1b86SEd Tanous } 2331e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2332e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23330f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23340f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2335002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2336002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2337c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "BMC Journal"; 2338e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23397c8c4058STejas Patil 23407c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23412b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2342002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23437c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23447c8c4058STejas Patil redfishDateTimeOffset.second; 23457c8c4058STejas Patil 23461476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23471476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23487e860f15SJohn Edward Broadbent }); 2349e1f26343SJason M. Bills } 2350e1f26343SJason M. Bills 23513a48b3a2SJason M. Bills static int 23523a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2353e1f26343SJason M. Bills sd_journal* journal, 23543a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2355e1f26343SJason M. Bills { 2356e1f26343SJason M. Bills // Get the Log Entry contents 2357e1f26343SJason M. Bills int ret = 0; 2358e1f26343SJason M. Bills 2359a8fe54f0SJason M. Bills std::string message; 2360a8fe54f0SJason M. Bills std::string_view syslogID; 2361a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2362a8fe54f0SJason M. Bills if (ret < 0) 2363a8fe54f0SJason M. Bills { 2364a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2365a8fe54f0SJason M. Bills << strerror(-ret); 2366a8fe54f0SJason M. Bills } 2367a8fe54f0SJason M. Bills if (!syslogID.empty()) 2368a8fe54f0SJason M. Bills { 2369a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2370a8fe54f0SJason M. Bills } 2371a8fe54f0SJason M. Bills 237239e77504SEd Tanous std::string_view msg; 237316428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2374e1f26343SJason M. Bills if (ret < 0) 2375e1f26343SJason M. Bills { 2376e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2377e1f26343SJason M. Bills return 1; 2378e1f26343SJason M. Bills } 2379a8fe54f0SJason M. Bills message += std::string(msg); 2380e1f26343SJason M. Bills 2381e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2382271584abSEd Tanous long int severity = 8; // Default to an invalid priority 238316428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2384e1f26343SJason M. Bills if (ret < 0) 2385e1f26343SJason M. Bills { 2386e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2387e1f26343SJason M. Bills } 2388e1f26343SJason M. Bills 2389e1f26343SJason M. Bills // Get the Created time from the timestamp 239016428a1aSJason M. Bills std::string entryTimeStr; 239116428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2392e1f26343SJason M. Bills { 239316428a1aSJason M. Bills return 1; 2394e1f26343SJason M. Bills } 2395e1f26343SJason M. Bills 2396e1f26343SJason M. Bills // Fill in the log entry with the gathered data 23979c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 239884afc48bSJason M. Bills bmcJournalLogEntryJson["@odata.id"] = 239984afc48bSJason M. Bills "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" + 240084afc48bSJason M. Bills bmcJournalLogEntryID; 240184afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 240284afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 240384afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 240484afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 240584afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2406738c1e61SPatrick Williams : severity <= 4 ? "Warning" 240784afc48bSJason M. Bills : "OK"; 240884afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 240984afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2410e1f26343SJason M. Bills return 0; 2411e1f26343SJason M. Bills } 2412e1f26343SJason M. Bills 24137e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2414e1f26343SJason M. Bills { 24157e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2416ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2417002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2418002d39b4SEd Tanous [&app](const crow::Request& req, 2419002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2420c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2421c937d2bfSEd Tanous .canDelegateTop = true, 2422c937d2bfSEd Tanous .canDelegateSkip = true, 2423c937d2bfSEd Tanous }; 2424c937d2bfSEd Tanous query_param::Query delegatedQuery; 2425c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24263ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2427193ad2faSJason M. Bills { 2428193ad2faSJason M. Bills return; 2429193ad2faSJason M. Bills } 24303648c8beSEd Tanous 24313648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24325143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24333648c8beSEd Tanous 24347e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24357e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2436e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2437e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24380f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24390f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2440e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2441e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2442e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24430fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2444e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2445e1f26343SJason M. Bills 24467e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24477e860f15SJohn Edward Broadbent // unique ID for each entry 2448e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2449e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2450e1f26343SJason M. Bills if (ret < 0) 2451e1f26343SJason M. Bills { 2452002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2453f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2454e1f26343SJason M. Bills return; 2455e1f26343SJason M. Bills } 24560fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 24570fda0f12SGeorge Liu journalTmp, sd_journal_close); 2458e1f26343SJason M. Bills journalTmp = nullptr; 2459b01bf299SEd Tanous uint64_t entryCount = 0; 2460e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2461e85d6b16SJason M. Bills bool firstEntry = true; 2462e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2463e1f26343SJason M. Bills { 2464193ad2faSJason M. Bills entryCount++; 24657e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 24667e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 24673648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2468193ad2faSJason M. Bills { 2469193ad2faSJason M. Bills continue; 2470193ad2faSJason M. Bills } 2471193ad2faSJason M. Bills 247216428a1aSJason M. Bills std::string idStr; 2473e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2474e1f26343SJason M. Bills { 2475e1f26343SJason M. Bills continue; 2476e1f26343SJason M. Bills } 2477e85d6b16SJason M. Bills firstEntry = false; 2478e85d6b16SJason M. Bills 24793a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2480c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2481c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2482e1f26343SJason M. Bills { 2483f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2484e1f26343SJason M. Bills return; 2485e1f26343SJason M. Bills } 24863a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2487e1f26343SJason M. Bills } 2488193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 24893648c8beSEd Tanous if (skip + top < entryCount) 2490193ad2faSJason M. Bills { 2491193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 24920fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 24933648c8beSEd Tanous std::to_string(skip + top); 2494193ad2faSJason M. Bills } 24957e860f15SJohn Edward Broadbent }); 2496e1f26343SJason M. Bills } 2497e1f26343SJason M. Bills 24987e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2499e1f26343SJason M. Bills { 25007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 25017e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2502ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 25037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 250445ca1b86SEd Tanous [&app](const crow::Request& req, 25057e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25067e860f15SJohn Edward Broadbent const std::string& entryID) { 25073ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 250845ca1b86SEd Tanous { 250945ca1b86SEd Tanous return; 251045ca1b86SEd Tanous } 2511e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2512e1f26343SJason M. Bills uint64_t ts = 0; 2513271584abSEd Tanous uint64_t index = 0; 25148d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2515e1f26343SJason M. Bills { 251616428a1aSJason M. Bills return; 2517e1f26343SJason M. Bills } 2518e1f26343SJason M. Bills 2519e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2520e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2521e1f26343SJason M. Bills if (ret < 0) 2522e1f26343SJason M. Bills { 2523002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2524f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2525e1f26343SJason M. Bills return; 2526e1f26343SJason M. Bills } 2527002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2528002d39b4SEd Tanous journalTmp, sd_journal_close); 2529e1f26343SJason M. Bills journalTmp = nullptr; 25307e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25317e860f15SJohn Edward Broadbent // index tracking the unique ID 2532af07e3f5SJason M. Bills std::string idStr; 2533af07e3f5SJason M. Bills bool firstEntry = true; 2534e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25352056b6d1SManojkiran Eda if (ret < 0) 25362056b6d1SManojkiran Eda { 25372056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25382056b6d1SManojkiran Eda << strerror(-ret); 25392056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25402056b6d1SManojkiran Eda return; 25412056b6d1SManojkiran Eda } 2542271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2543e1f26343SJason M. Bills { 2544e1f26343SJason M. Bills sd_journal_next(journal.get()); 2545af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2546af07e3f5SJason M. Bills { 2547af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2548af07e3f5SJason M. Bills return; 2549af07e3f5SJason M. Bills } 2550af07e3f5SJason M. Bills firstEntry = false; 2551af07e3f5SJason M. Bills } 2552c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2553af07e3f5SJason M. Bills if (idStr != entryID) 2554c4bf6374SJason M. Bills { 25559db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2556c4bf6374SJason M. Bills return; 2557c4bf6374SJason M. Bills } 2558c4bf6374SJason M. Bills 25593a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2560c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 25613a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2562e1f26343SJason M. Bills { 2563f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2564e1f26343SJason M. Bills return; 2565e1f26343SJason M. Bills } 2566d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 25677e860f15SJohn Edward Broadbent }); 2568c9bb6861Sraviteja-b } 2569c9bb6861Sraviteja-b 2570fdd26906SClaire Weinan inline void 2571fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2572fdd26906SClaire Weinan const std::string& dumpType) 2573c9bb6861Sraviteja-b { 2574fdd26906SClaire Weinan std::string dumpPath; 2575fdd26906SClaire Weinan std::string overWritePolicy; 2576fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2577fdd26906SClaire Weinan 2578fdd26906SClaire Weinan if (dumpType == "BMC") 257945ca1b86SEd Tanous { 2580fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2581fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2582fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2583fdd26906SClaire Weinan } 2584fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2585fdd26906SClaire Weinan { 2586fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2587fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2588fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2589fdd26906SClaire Weinan } 2590fdd26906SClaire Weinan else if (dumpType == "System") 2591fdd26906SClaire Weinan { 2592fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2593fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2594fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2595fdd26906SClaire Weinan } 2596fdd26906SClaire Weinan else 2597fdd26906SClaire Weinan { 2598fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2599fdd26906SClaire Weinan << dumpType; 2600fdd26906SClaire Weinan messages::internalError(asyncResp->res); 260145ca1b86SEd Tanous return; 260245ca1b86SEd Tanous } 2603fdd26906SClaire Weinan 2604fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2605fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2606c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2607fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2608fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2609fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 26107c8c4058STejas Patil 26117c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 26122b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 26130fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 26147c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 26157c8c4058STejas Patil redfishDateTimeOffset.second; 26167c8c4058STejas Patil 2617fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2618002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 2619fdd26906SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 2620fdd26906SClaire Weinan 2621fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2622fdd26906SClaire Weinan { 2623002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26241476687dSEd Tanous ["target"] = 2625fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2626fdd26906SClaire Weinan } 2627c9bb6861Sraviteja-b } 2628c9bb6861Sraviteja-b 2629fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2630fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2631fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 26327e860f15SJohn Edward Broadbent { 26333ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 263445ca1b86SEd Tanous { 263545ca1b86SEd Tanous return; 263645ca1b86SEd Tanous } 2637fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2638fdd26906SClaire Weinan } 2639c9bb6861Sraviteja-b 264022d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 264122d268cbSEd Tanous crow::App& app, const crow::Request& req, 264222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 264322d268cbSEd Tanous const std::string& chassisId) 264422d268cbSEd Tanous { 264522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 264622d268cbSEd Tanous { 264722d268cbSEd Tanous return; 264822d268cbSEd Tanous } 264922d268cbSEd Tanous if (chassisId != "system") 265022d268cbSEd Tanous { 265122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 265222d268cbSEd Tanous return; 265322d268cbSEd Tanous } 265422d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 265522d268cbSEd Tanous } 265622d268cbSEd Tanous 2657fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2658fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2659fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2660fdd26906SClaire Weinan { 2661fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2662fdd26906SClaire Weinan { 2663fdd26906SClaire Weinan return; 2664fdd26906SClaire Weinan } 2665fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2666fdd26906SClaire Weinan } 2667fdd26906SClaire Weinan 266822d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 266922d268cbSEd Tanous crow::App& app, const crow::Request& req, 267022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 267122d268cbSEd Tanous const std::string& chassisId) 267222d268cbSEd Tanous { 267322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 267422d268cbSEd Tanous { 267522d268cbSEd Tanous return; 267622d268cbSEd Tanous } 267722d268cbSEd Tanous if (chassisId != "system") 267822d268cbSEd Tanous { 267922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 268022d268cbSEd Tanous return; 268122d268cbSEd Tanous } 268222d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 268322d268cbSEd Tanous } 268422d268cbSEd Tanous 2685fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2686fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2687fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2688fdd26906SClaire Weinan const std::string& dumpId) 2689fdd26906SClaire Weinan { 2690fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2691fdd26906SClaire Weinan { 2692fdd26906SClaire Weinan return; 2693fdd26906SClaire Weinan } 2694fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2695fdd26906SClaire Weinan } 269622d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 269722d268cbSEd Tanous crow::App& app, const crow::Request& req, 269822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 269922d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 270022d268cbSEd Tanous { 270122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270222d268cbSEd Tanous { 270322d268cbSEd Tanous return; 270422d268cbSEd Tanous } 270522d268cbSEd Tanous if (chassisId != "system") 270622d268cbSEd Tanous { 270722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 270822d268cbSEd Tanous return; 270922d268cbSEd Tanous } 271022d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 271122d268cbSEd Tanous } 2712fdd26906SClaire Weinan 2713fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2714fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2715fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2716fdd26906SClaire Weinan const std::string& dumpId) 2717fdd26906SClaire Weinan { 2718fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2719fdd26906SClaire Weinan { 2720fdd26906SClaire Weinan return; 2721fdd26906SClaire Weinan } 2722fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2723fdd26906SClaire Weinan } 2724fdd26906SClaire Weinan 272522d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 272622d268cbSEd Tanous crow::App& app, const crow::Request& req, 272722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 272822d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 272922d268cbSEd Tanous { 273022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 273122d268cbSEd Tanous { 273222d268cbSEd Tanous return; 273322d268cbSEd Tanous } 273422d268cbSEd Tanous if (chassisId != "system") 273522d268cbSEd Tanous { 273622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 273722d268cbSEd Tanous return; 273822d268cbSEd Tanous } 273922d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 274022d268cbSEd Tanous } 274122d268cbSEd Tanous 2742fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2743fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2744fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2745fdd26906SClaire Weinan { 2746fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2747fdd26906SClaire Weinan { 2748fdd26906SClaire Weinan return; 2749fdd26906SClaire Weinan } 2750fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2751fdd26906SClaire Weinan } 2752fdd26906SClaire Weinan 275322d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 275422d268cbSEd Tanous crow::App& app, const crow::Request& req, 275522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 275622d268cbSEd Tanous const std::string& chassisId) 275722d268cbSEd Tanous { 275822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 275922d268cbSEd Tanous { 276022d268cbSEd Tanous return; 276122d268cbSEd Tanous } 276222d268cbSEd Tanous if (chassisId != "system") 276322d268cbSEd Tanous { 276422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 276522d268cbSEd Tanous return; 276622d268cbSEd Tanous } 276722d268cbSEd Tanous createDump(asyncResp, req, "System"); 276822d268cbSEd Tanous } 276922d268cbSEd Tanous 2770fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2771fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2772fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2773fdd26906SClaire Weinan { 2774fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2775fdd26906SClaire Weinan { 2776fdd26906SClaire Weinan return; 2777fdd26906SClaire Weinan } 2778fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2779fdd26906SClaire Weinan } 2780fdd26906SClaire Weinan 278122d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 278222d268cbSEd Tanous crow::App& app, const crow::Request& req, 278322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 278422d268cbSEd Tanous const std::string& chassisId) 278522d268cbSEd Tanous { 278622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 278722d268cbSEd Tanous { 278822d268cbSEd Tanous return; 278922d268cbSEd Tanous } 279022d268cbSEd Tanous if (chassisId != "system") 279122d268cbSEd Tanous { 279222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 279322d268cbSEd Tanous return; 279422d268cbSEd Tanous } 279522d268cbSEd Tanous clearDump(asyncResp, "System"); 279622d268cbSEd Tanous } 279722d268cbSEd Tanous 2798fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2799fdd26906SClaire Weinan { 2800fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2801fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2802fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2803fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2804fdd26906SClaire Weinan } 2805fdd26906SClaire Weinan 2806fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2807fdd26906SClaire Weinan { 2808fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2809fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2810fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2811fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2812c9bb6861Sraviteja-b } 2813c9bb6861Sraviteja-b 28147e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2815c9bb6861Sraviteja-b { 28167e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28177e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2818ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2819fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2820fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2821fdd26906SClaire Weinan 28227e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28237e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2824ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2825fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2826fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2827c9bb6861Sraviteja-b } 2828c9bb6861Sraviteja-b 28297e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2830c9bb6861Sraviteja-b { 28310fda0f12SGeorge Liu BMCWEB_ROUTE( 28320fda0f12SGeorge Liu app, 28330fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2834ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28357e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2836fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2837fdd26906SClaire Weinan std::ref(app), "BMC")); 2838a43be80fSAsmitha Karunanithi } 2839a43be80fSAsmitha Karunanithi 28407e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 284180319af1SAsmitha Karunanithi { 28420fda0f12SGeorge Liu BMCWEB_ROUTE( 28430fda0f12SGeorge Liu app, 28440fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2845ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2846fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2847fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 284845ca1b86SEd Tanous } 2849fdd26906SClaire Weinan 2850fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2851fdd26906SClaire Weinan { 2852fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2853fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2854fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2855fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2856fdd26906SClaire Weinan } 2857fdd26906SClaire Weinan 2858fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2859fdd26906SClaire Weinan { 2860fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2861fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2862fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2863fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2864fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2865fdd26906SClaire Weinan } 2866fdd26906SClaire Weinan 2867fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2868fdd26906SClaire Weinan { 2869fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2870fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2871fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2872fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2873fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2874fdd26906SClaire Weinan 2875fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2876fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2877fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2878fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2879fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2880fdd26906SClaire Weinan } 2881fdd26906SClaire Weinan 2882fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2883fdd26906SClaire Weinan { 2884fdd26906SClaire Weinan BMCWEB_ROUTE( 2885fdd26906SClaire Weinan app, 2886fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2887fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2888fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2889fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 28905cb1dd27SAsmitha Karunanithi } 28915cb1dd27SAsmitha Karunanithi 28927e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 28935cb1dd27SAsmitha Karunanithi { 289422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2895ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 28966ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 289722d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 28985cb1dd27SAsmitha Karunanithi } 28995cb1dd27SAsmitha Karunanithi 29007e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 29017e860f15SJohn Edward Broadbent { 290222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2903ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 290422d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 290522d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 290622d268cbSEd Tanous std::ref(app))); 29075cb1dd27SAsmitha Karunanithi } 29085cb1dd27SAsmitha Karunanithi 29097e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 29105cb1dd27SAsmitha Karunanithi { 29117e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 291222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2913ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29146ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 291522d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29168d1b46d7Szhanghch05 29177e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 291822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2919ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29206ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 292122d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29225cb1dd27SAsmitha Karunanithi } 2923c9bb6861Sraviteja-b 29247e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2925c9bb6861Sraviteja-b { 29260fda0f12SGeorge Liu BMCWEB_ROUTE( 29270fda0f12SGeorge Liu app, 292822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2929ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 293022d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 293122d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 293222d268cbSEd Tanous std::ref(app))); 2933a43be80fSAsmitha Karunanithi } 2934a43be80fSAsmitha Karunanithi 29357e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2936a43be80fSAsmitha Karunanithi { 29370fda0f12SGeorge Liu BMCWEB_ROUTE( 29380fda0f12SGeorge Liu app, 293922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2940ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29416ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 294222d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2943013487e5Sraviteja-b } 2944013487e5Sraviteja-b 29457e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29461da66f75SEd Tanous { 29473946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29483946028dSAppaRao Puli // method for security reasons. 29491da66f75SEd Tanous /** 29501da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29511da66f75SEd Tanous */ 295222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2953ed398213SEd Tanous // This is incorrect, should be: 2954ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2955432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2956002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2957002d39b4SEd Tanous [&app](const crow::Request& req, 295822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 295922d268cbSEd Tanous const std::string& systemName) { 29603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 296145ca1b86SEd Tanous { 296245ca1b86SEd Tanous return; 296345ca1b86SEd Tanous } 296422d268cbSEd Tanous if (systemName != "system") 296522d268cbSEd Tanous { 296622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 296722d268cbSEd Tanous systemName); 296822d268cbSEd Tanous return; 296922d268cbSEd Tanous } 297022d268cbSEd Tanous 29717e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29727e860f15SJohn Edward Broadbent // SubRoute 29730f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2974424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 2975e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 29768e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 29774f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 29784f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 29794f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 2980e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 2981e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 29827c8c4058STejas Patil 29837c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 29842b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 29857c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 29867c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 29877c8c4058STejas Patil redfishDateTimeOffset.second; 29887c8c4058STejas Patil 29891476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 29901476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 2991002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 29921476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 2993002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 29941476687dSEd Tanous ["target"] = 29951476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 29967e860f15SJohn Edward Broadbent }); 29971da66f75SEd Tanous } 29981da66f75SEd Tanous 29997e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30005b61b5e8SJason M. Bills { 30010fda0f12SGeorge Liu BMCWEB_ROUTE( 30020fda0f12SGeorge Liu app, 300322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3004ed398213SEd Tanous // This is incorrect, should be: 3005ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3006432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30077e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 300845ca1b86SEd Tanous [&app](const crow::Request& req, 300922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 301022d268cbSEd Tanous const std::string& systemName) { 30113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 301245ca1b86SEd Tanous { 301345ca1b86SEd Tanous return; 301445ca1b86SEd Tanous } 301522d268cbSEd Tanous if (systemName != "system") 301622d268cbSEd Tanous { 301722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 301822d268cbSEd Tanous systemName); 301922d268cbSEd Tanous return; 302022d268cbSEd Tanous } 30215b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30225b61b5e8SJason M. Bills [asyncResp](const boost::system::error_code ec, 3023cb13a392SEd Tanous const std::string&) { 30245b61b5e8SJason M. Bills if (ec) 30255b61b5e8SJason M. Bills { 30265b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30275b61b5e8SJason M. Bills return; 30285b61b5e8SJason M. Bills } 30295b61b5e8SJason M. Bills messages::success(asyncResp->res); 30305b61b5e8SJason M. Bills }, 3031002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30327e860f15SJohn Edward Broadbent }); 30335b61b5e8SJason M. Bills } 30345b61b5e8SJason M. Bills 30358d1b46d7Szhanghch05 static void 30368d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30378d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3038e855dd28SJason M. Bills { 3039043a0536SJohnathan Mantey auto getStoredLogCallback = 3040b9d36b47SEd Tanous [asyncResp, logID, 3041b9d36b47SEd Tanous &logEntryJson](const boost::system::error_code ec, 3042b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3043e855dd28SJason M. Bills if (ec) 3044e855dd28SJason M. Bills { 3045e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 30461ddcf01aSJason M. Bills if (ec.value() == 30471ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30481ddcf01aSJason M. Bills { 3049002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30501ddcf01aSJason M. Bills } 30511ddcf01aSJason M. Bills else 30521ddcf01aSJason M. Bills { 3053e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30541ddcf01aSJason M. Bills } 3055e855dd28SJason M. Bills return; 3056e855dd28SJason M. Bills } 3057043a0536SJohnathan Mantey 3058043a0536SJohnathan Mantey std::string timestamp{}; 3059043a0536SJohnathan Mantey std::string filename{}; 3060043a0536SJohnathan Mantey std::string logfile{}; 30612c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3062043a0536SJohnathan Mantey 3063043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3064e855dd28SJason M. Bills { 30659db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3066e855dd28SJason M. Bills return; 3067e855dd28SJason M. Bills } 3068e855dd28SJason M. Bills 3069043a0536SJohnathan Mantey std::string crashdumpURI = 3070e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3071043a0536SJohnathan Mantey logID + "/" + filename; 307284afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30739c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 307484afc48bSJason M. Bills logEntry["@odata.id"] = 307584afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID; 307684afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 307784afc48bSJason M. Bills logEntry["Id"] = logID; 307884afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 307984afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 308084afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 308184afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 308284afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 30832b20ef6eSJason M. Bills 30842b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 30852b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 30862b20ef6eSJason M. Bills // directly 30872b20ef6eSJason M. Bills if (logEntryJson.is_array()) 30882b20ef6eSJason M. Bills { 30892b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 30902b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 30912b20ef6eSJason M. Bills logEntryJson.size(); 30922b20ef6eSJason M. Bills } 30932b20ef6eSJason M. Bills else 30942b20ef6eSJason M. Bills { 3095d405bb51SJason M. Bills logEntryJson.update(logEntry); 30962b20ef6eSJason M. Bills } 3097e855dd28SJason M. Bills }; 3098d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3099d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3100d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3101d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3102e855dd28SJason M. Bills } 3103e855dd28SJason M. Bills 31047e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31051da66f75SEd Tanous { 31063946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31073946028dSAppaRao Puli // method for security reasons. 31081da66f75SEd Tanous /** 31091da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31101da66f75SEd Tanous */ 31117e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 311222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3113ed398213SEd Tanous // This is incorrect, should be. 3114ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3115432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3116002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3117002d39b4SEd Tanous [&app](const crow::Request& req, 311822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 311922d268cbSEd Tanous const std::string& systemName) { 31203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 312145ca1b86SEd Tanous { 312245ca1b86SEd Tanous return; 312345ca1b86SEd Tanous } 312422d268cbSEd Tanous if (systemName != "system") 312522d268cbSEd Tanous { 312622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 312722d268cbSEd Tanous systemName); 312822d268cbSEd Tanous return; 312922d268cbSEd Tanous } 313022d268cbSEd Tanous 31312b20ef6eSJason M. Bills crow::connections::systemBus->async_method_call( 31322b20ef6eSJason M. Bills [asyncResp](const boost::system::error_code ec, 31332b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31341da66f75SEd Tanous if (ec) 31351da66f75SEd Tanous { 31361da66f75SEd Tanous if (ec.value() != 31371da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31381da66f75SEd Tanous { 31391da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 31401da66f75SEd Tanous << ec.message(); 3141f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31421da66f75SEd Tanous return; 31431da66f75SEd Tanous } 31441da66f75SEd Tanous } 3145e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31461da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 31470f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3148424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3149002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3150e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3151424c4176SJason M. Bills "Collection of Crashdump Entries"; 3152002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3153a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31542b20ef6eSJason M. Bills 31552b20ef6eSJason M. Bills for (const std::string& path : resp) 31561da66f75SEd Tanous { 31572b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3158e855dd28SJason M. Bills // Get the log ID 31592b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31602b20ef6eSJason M. Bills if (logID.empty()) 31611da66f75SEd Tanous { 3162e855dd28SJason M. Bills continue; 31631da66f75SEd Tanous } 3164e855dd28SJason M. Bills // Add the log entry to the array 31652b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31662b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31671da66f75SEd Tanous } 31682b20ef6eSJason M. Bills }, 31691da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", 31701da66f75SEd Tanous "/xyz/openbmc_project/object_mapper", 31711da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0, 31725b61b5e8SJason M. Bills std::array<const char*, 1>{crashdumpInterface}); 31737e860f15SJohn Edward Broadbent }); 31741da66f75SEd Tanous } 31751da66f75SEd Tanous 31767e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31771da66f75SEd Tanous { 31783946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31793946028dSAppaRao Puli // method for security reasons. 31801da66f75SEd Tanous 31817e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 318222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3183ed398213SEd Tanous // this is incorrect, should be 3184ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3185432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 31867e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 318745ca1b86SEd Tanous [&app](const crow::Request& req, 31887e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 318922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 31903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 319145ca1b86SEd Tanous { 319245ca1b86SEd Tanous return; 319345ca1b86SEd Tanous } 319422d268cbSEd Tanous if (systemName != "system") 319522d268cbSEd Tanous { 319622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 319722d268cbSEd Tanous systemName); 319822d268cbSEd Tanous ; 319922d268cbSEd Tanous return; 320022d268cbSEd Tanous } 32017e860f15SJohn Edward Broadbent const std::string& logID = param; 3202e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32037e860f15SJohn Edward Broadbent }); 3204e855dd28SJason M. Bills } 3205e855dd28SJason M. Bills 32067e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3207e855dd28SJason M. Bills { 32083946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32093946028dSAppaRao Puli // method for security reasons. 32107e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32117e860f15SJohn Edward Broadbent app, 321222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3213ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32147e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3215a4ce114aSNan Zhou [](const crow::Request& req, 32167e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 321722d268cbSEd Tanous const std::string& systemName, const std::string& logID, 321822d268cbSEd Tanous const std::string& fileName) { 32192a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32202a9beeedSShounak Mitra // Redfish resource. 322122d268cbSEd Tanous 322222d268cbSEd Tanous if (systemName != "system") 322322d268cbSEd Tanous { 322422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 322522d268cbSEd Tanous systemName); 322622d268cbSEd Tanous ; 322722d268cbSEd Tanous return; 322822d268cbSEd Tanous } 322922d268cbSEd Tanous 3230043a0536SJohnathan Mantey auto getStoredLogCallback = 3231002d39b4SEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))]( 3232abf2add6SEd Tanous const boost::system::error_code ec, 3233002d39b4SEd Tanous const std::vector< 3234002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32357e860f15SJohn Edward Broadbent resp) { 32361da66f75SEd Tanous if (ec) 32371da66f75SEd Tanous { 3238002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3239f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32401da66f75SEd Tanous return; 32411da66f75SEd Tanous } 3242e855dd28SJason M. Bills 3243043a0536SJohnathan Mantey std::string dbusFilename{}; 3244043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3245043a0536SJohnathan Mantey std::string dbusFilepath{}; 3246043a0536SJohnathan Mantey 3247002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3248002d39b4SEd Tanous dbusFilepath); 3249043a0536SJohnathan Mantey 3250043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3251043a0536SJohnathan Mantey dbusFilepath.empty()) 32521da66f75SEd Tanous { 32539db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32541da66f75SEd Tanous return; 32551da66f75SEd Tanous } 3256e855dd28SJason M. Bills 3257043a0536SJohnathan Mantey // Verify the file name parameter is correct 3258043a0536SJohnathan Mantey if (fileName != dbusFilename) 3259043a0536SJohnathan Mantey { 32609db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3261043a0536SJohnathan Mantey return; 3262043a0536SJohnathan Mantey } 3263043a0536SJohnathan Mantey 3264043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3265043a0536SJohnathan Mantey { 32669db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3267043a0536SJohnathan Mantey return; 3268043a0536SJohnathan Mantey } 3269002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3270002d39b4SEd Tanous asyncResp->res.body() = 3271002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3272043a0536SJohnathan Mantey 32737e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32747e860f15SJohn Edward Broadbent // from a browser 3275d9f6c621SEd Tanous asyncResp->res.addHeader( 3276d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 32771da66f75SEd Tanous }; 3278d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3279d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3280d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3281d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 32827e860f15SJohn Edward Broadbent }); 32831da66f75SEd Tanous } 32841da66f75SEd Tanous 3285c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3286c5a4c82aSJason M. Bills { 3287c5a4c82aSJason M. Bills onDemand, 3288c5a4c82aSJason M. Bills telemetry, 3289c5a4c82aSJason M. Bills invalid, 3290c5a4c82aSJason M. Bills }; 3291c5a4c82aSJason M. Bills 3292f7725d79SEd Tanous inline OEMDiagnosticType 3293f7725d79SEd Tanous getOEMDiagnosticType(const std::string_view& oemDiagStr) 3294c5a4c82aSJason M. Bills { 3295c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3296c5a4c82aSJason M. Bills { 3297c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3298c5a4c82aSJason M. Bills } 3299c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3300c5a4c82aSJason M. Bills { 3301c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3302c5a4c82aSJason M. Bills } 3303c5a4c82aSJason M. Bills 3304c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3305c5a4c82aSJason M. Bills } 3306c5a4c82aSJason M. Bills 33077e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33081da66f75SEd Tanous { 33093946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33103946028dSAppaRao Puli // method for security reasons. 33110fda0f12SGeorge Liu BMCWEB_ROUTE( 33120fda0f12SGeorge Liu app, 331322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3314ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3315ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3316432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3317002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3318002d39b4SEd Tanous [&app](const crow::Request& req, 331922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 332022d268cbSEd Tanous const std::string& systemName) { 33213ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 332245ca1b86SEd Tanous { 332345ca1b86SEd Tanous return; 332445ca1b86SEd Tanous } 332522d268cbSEd Tanous 332622d268cbSEd Tanous if (systemName != "system") 332722d268cbSEd Tanous { 332822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 332922d268cbSEd Tanous systemName); 333022d268cbSEd Tanous ; 333122d268cbSEd Tanous return; 333222d268cbSEd Tanous } 333322d268cbSEd Tanous 33348e6c099aSJason M. Bills std::string diagnosticDataType; 33358e6c099aSJason M. Bills std::string oemDiagnosticDataType; 333615ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3337002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3338002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33398e6c099aSJason M. Bills { 33408e6c099aSJason M. Bills return; 33418e6c099aSJason M. Bills } 33428e6c099aSJason M. Bills 33438e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33448e6c099aSJason M. Bills { 33458e6c099aSJason M. Bills BMCWEB_LOG_ERROR 33468e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 33478e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33488e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33498e6c099aSJason M. Bills "CollectDiagnosticData"); 33508e6c099aSJason M. Bills return; 33518e6c099aSJason M. Bills } 33528e6c099aSJason M. Bills 3353c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3354c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3355c5a4c82aSJason M. Bills 3356c5a4c82aSJason M. Bills std::string iface; 3357c5a4c82aSJason M. Bills std::string method; 3358c5a4c82aSJason M. Bills std::string taskMatchStr; 3359c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3360c5a4c82aSJason M. Bills { 3361c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3362c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3363c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3364c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3365c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3366c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3367c5a4c82aSJason M. Bills } 3368c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3369c5a4c82aSJason M. Bills { 3370c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3371c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3372c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3373c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3374c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3375c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3376c5a4c82aSJason M. Bills } 3377c5a4c82aSJason M. Bills else 3378c5a4c82aSJason M. Bills { 3379c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3380c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3381c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3382002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3383002d39b4SEd Tanous "CollectDiagnosticData"); 3384c5a4c82aSJason M. Bills return; 3385c5a4c82aSJason M. Bills } 3386c5a4c82aSJason M. Bills 3387c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3388c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 3389c5a4c82aSJason M. Bills taskMatchStr](const boost::system::error_code ec, 339098be3e39SEd Tanous const std::string&) mutable { 33911da66f75SEd Tanous if (ec) 33921da66f75SEd Tanous { 3393002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 33941da66f75SEd Tanous { 3395f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 33961da66f75SEd Tanous } 33974363d3b2SJason M. Bills else if (ec.value() == 33984363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 33994363d3b2SJason M. Bills { 3400002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3401002d39b4SEd Tanous "60"); 34024363d3b2SJason M. Bills } 34031da66f75SEd Tanous else 34041da66f75SEd Tanous { 3405f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34061da66f75SEd Tanous } 34071da66f75SEd Tanous return; 34081da66f75SEd Tanous } 3409002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 341059d494eeSPatrick Williams [](boost::system::error_code err, sdbusplus::message_t&, 3411002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 341266afe4faSJames Feist if (!err) 341366afe4faSJames Feist { 3414002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3415e5d5006bSJames Feist std::to_string(taskData->index))); 3416831d6b09SJames Feist taskData->state = "Completed"; 341766afe4faSJames Feist } 341832898ceaSJames Feist return task::completed; 341966afe4faSJames Feist }, 3420c5a4c82aSJason M. Bills taskMatchStr); 3421c5a4c82aSJason M. Bills 342246229577SJames Feist task->startTimer(std::chrono::minutes(5)); 342346229577SJames Feist task->populateResp(asyncResp->res); 342498be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34251da66f75SEd Tanous }; 34268e6c099aSJason M. Bills 34271da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3428002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3429002d39b4SEd Tanous iface, method); 34307e860f15SJohn Edward Broadbent }); 34316eda7685SKenny L. Ku } 34326eda7685SKenny L. Ku 3433cb92c03bSAndrew Geissler /** 3434cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3435cb92c03bSAndrew Geissler */ 34367e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3437cb92c03bSAndrew Geissler { 3438cb92c03bSAndrew Geissler /** 3439cb92c03bSAndrew Geissler * Function handles POST method request. 3440cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3441cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3442cb92c03bSAndrew Geissler */ 34437e860f15SJohn Edward Broadbent 34440fda0f12SGeorge Liu BMCWEB_ROUTE( 34450fda0f12SGeorge Liu app, 344622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3447ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 344945ca1b86SEd Tanous [&app](const crow::Request& req, 345022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 345122d268cbSEd Tanous const std::string& systemName) { 34523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 345345ca1b86SEd Tanous { 345445ca1b86SEd Tanous return; 345545ca1b86SEd Tanous } 345622d268cbSEd Tanous if (systemName != "system") 345722d268cbSEd Tanous { 345822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 345922d268cbSEd Tanous systemName); 346022d268cbSEd Tanous ; 346122d268cbSEd Tanous return; 346222d268cbSEd Tanous } 3463cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3464cb92c03bSAndrew Geissler 3465cb92c03bSAndrew Geissler // Process response from Logging service. 3466002d39b4SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code ec) { 3467002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3468cb92c03bSAndrew Geissler if (ec) 3469cb92c03bSAndrew Geissler { 3470cb92c03bSAndrew Geissler // TODO Handle for specific error code 3471002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3472cb92c03bSAndrew Geissler asyncResp->res.result( 3473cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3474cb92c03bSAndrew Geissler return; 3475cb92c03bSAndrew Geissler } 3476cb92c03bSAndrew Geissler 3477002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3478cb92c03bSAndrew Geissler }; 3479cb92c03bSAndrew Geissler 3480cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3481cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 34822c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3483cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3484cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 34857e860f15SJohn Edward Broadbent }); 3486cb92c03bSAndrew Geissler } 3487a3316fc6SZhikuiRen 3488a3316fc6SZhikuiRen /**************************************************** 3489a3316fc6SZhikuiRen * Redfish PostCode interfaces 3490a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3491a3316fc6SZhikuiRen ******************************************************/ 34927e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3493a3316fc6SZhikuiRen { 349422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3495ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3496002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3497002d39b4SEd Tanous [&app](const crow::Request& req, 349822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 349922d268cbSEd Tanous const std::string& systemName) { 35003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 350145ca1b86SEd Tanous { 350245ca1b86SEd Tanous return; 350345ca1b86SEd Tanous } 350422d268cbSEd Tanous if (systemName != "system") 350522d268cbSEd Tanous { 350622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 350722d268cbSEd Tanous systemName); 350822d268cbSEd Tanous ; 350922d268cbSEd Tanous return; 351022d268cbSEd Tanous } 35111476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 35121476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 35131476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 35141476687dSEd Tanous "#LogService.v1_1_0.LogService"; 35151476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35161476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 35171476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log"; 35181476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35191476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35201476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35217c8c4058STejas Patil 35227c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35232b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35240fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35257c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35267c8c4058STejas Patil redfishDateTimeOffset.second; 35277c8c4058STejas Patil 3528a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 35297e860f15SJohn Edward Broadbent {"target", 35300fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 35317e860f15SJohn Edward Broadbent }); 3532a3316fc6SZhikuiRen } 3533a3316fc6SZhikuiRen 35347e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3535a3316fc6SZhikuiRen { 35360fda0f12SGeorge Liu BMCWEB_ROUTE( 35370fda0f12SGeorge Liu app, 353822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3539ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3540ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3541432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35427e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 354345ca1b86SEd Tanous [&app](const crow::Request& req, 354422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 354522d268cbSEd Tanous const std::string& systemName) { 35463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 354745ca1b86SEd Tanous { 354845ca1b86SEd Tanous return; 354945ca1b86SEd Tanous } 355022d268cbSEd Tanous if (systemName != "system") 355122d268cbSEd Tanous { 355222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 355322d268cbSEd Tanous systemName); 355422d268cbSEd Tanous ; 355522d268cbSEd Tanous return; 355622d268cbSEd Tanous } 3557a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3558a3316fc6SZhikuiRen 3559a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3560a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3561a3316fc6SZhikuiRen [asyncResp](const boost::system::error_code ec) { 3562a3316fc6SZhikuiRen if (ec) 3563a3316fc6SZhikuiRen { 3564a3316fc6SZhikuiRen // TODO Handle for specific error code 3565002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 35667e860f15SJohn Edward Broadbent << ec; 3567002d39b4SEd Tanous asyncResp->res.result( 3568002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3569a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3570a3316fc6SZhikuiRen return; 3571a3316fc6SZhikuiRen } 3572a3316fc6SZhikuiRen }, 357315124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 357415124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3575a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35767e860f15SJohn Edward Broadbent }); 3577a3316fc6SZhikuiRen } 3578a3316fc6SZhikuiRen 3579a3316fc6SZhikuiRen static void fillPostCodeEntry( 35808d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 35816c9a279eSManojkiran Eda const boost::container::flat_map< 35826c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3583a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3584a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3585a3316fc6SZhikuiRen { 3586a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3587fffb8c1fSEd Tanous const registries::Message* message = 3588fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3589a3316fc6SZhikuiRen 3590a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3591a3316fc6SZhikuiRen nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 3592a3316fc6SZhikuiRen 3593a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 35946c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 35956c9a279eSManojkiran Eda code : postcode) 3596a3316fc6SZhikuiRen { 3597a3316fc6SZhikuiRen currentCodeIndex++; 3598a3316fc6SZhikuiRen std::string postcodeEntryID = 3599a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3600a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3601a3316fc6SZhikuiRen 3602a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3603a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3604a3316fc6SZhikuiRen 3605a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3606a3316fc6SZhikuiRen { // already incremented 3607a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3608a3316fc6SZhikuiRen } 3609a3316fc6SZhikuiRen else 3610a3316fc6SZhikuiRen { 3611a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3612a3316fc6SZhikuiRen } 3613a3316fc6SZhikuiRen 3614a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3615a3316fc6SZhikuiRen // not fall between top and skip 3616a3316fc6SZhikuiRen if ((codeIndex == 0) && 3617a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3618a3316fc6SZhikuiRen { 3619a3316fc6SZhikuiRen continue; 3620a3316fc6SZhikuiRen } 3621a3316fc6SZhikuiRen 36224e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3623a3316fc6SZhikuiRen // currentIndex 3624a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3625a3316fc6SZhikuiRen { 3626a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3627a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3628a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3629a3316fc6SZhikuiRen continue; 3630a3316fc6SZhikuiRen } 3631a3316fc6SZhikuiRen 3632a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3633a3316fc6SZhikuiRen // index 3634a3316fc6SZhikuiRen 3635a3316fc6SZhikuiRen // Get the Created time from the timestamp 3636a3316fc6SZhikuiRen std::string entryTimeStr; 36371d8782e7SNan Zhou entryTimeStr = 36382b82937eSEd Tanous redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000); 3639a3316fc6SZhikuiRen 3640a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3641a3316fc6SZhikuiRen std::ostringstream hexCode; 3642a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 36436c9a279eSManojkiran Eda << std::get<0>(code.second); 3644a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3645a3316fc6SZhikuiRen // Set Fixed -Point Notation 3646a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3647a3316fc6SZhikuiRen // Set precision to 4 digits 3648a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3649a3316fc6SZhikuiRen // Add double to stream 3650a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3651a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3652a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3653a3316fc6SZhikuiRen 3654a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3655a3316fc6SZhikuiRen std::string msg; 3656a3316fc6SZhikuiRen if (message != nullptr) 3657a3316fc6SZhikuiRen { 3658a3316fc6SZhikuiRen msg = message->message; 3659a3316fc6SZhikuiRen 3660a3316fc6SZhikuiRen // fill in this post code value 3661a3316fc6SZhikuiRen int i = 0; 3662a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3663a3316fc6SZhikuiRen { 3664a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3665a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3666a3316fc6SZhikuiRen if (argPos != std::string::npos) 3667a3316fc6SZhikuiRen { 3668a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3669a3316fc6SZhikuiRen } 3670a3316fc6SZhikuiRen } 3671a3316fc6SZhikuiRen } 3672a3316fc6SZhikuiRen 3673d4342a92STim Lee // Get Severity template from message registry 3674d4342a92STim Lee std::string severity; 3675d4342a92STim Lee if (message != nullptr) 3676d4342a92STim Lee { 36775f2b84eeSEd Tanous severity = message->messageSeverity; 3678d4342a92STim Lee } 3679d4342a92STim Lee 3680a3316fc6SZhikuiRen // add to AsyncResp 3681a3316fc6SZhikuiRen logEntryArray.push_back({}); 3682a3316fc6SZhikuiRen nlohmann::json& bmcLogEntry = logEntryArray.back(); 36839c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 368484afc48bSJason M. Bills bmcLogEntry["@odata.id"] = 36850fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 368684afc48bSJason M. Bills postcodeEntryID; 368784afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 368884afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 368984afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 369084afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 369184afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 369284afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 369384afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 369484afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3695647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3696647b3cdcSGeorge Liu { 3697647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3698647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3699647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3700647b3cdcSGeorge Liu } 3701a3316fc6SZhikuiRen } 3702a3316fc6SZhikuiRen } 3703a3316fc6SZhikuiRen 37048d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3705a3316fc6SZhikuiRen const uint16_t bootIndex, 3706a3316fc6SZhikuiRen const uint64_t codeIndex) 3707a3316fc6SZhikuiRen { 3708a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 37096c9a279eSManojkiran Eda [aResp, bootIndex, 37106c9a279eSManojkiran Eda codeIndex](const boost::system::error_code ec, 37116c9a279eSManojkiran Eda const boost::container::flat_map< 37126c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37136c9a279eSManojkiran Eda postcode) { 3714a3316fc6SZhikuiRen if (ec) 3715a3316fc6SZhikuiRen { 3716a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3717a3316fc6SZhikuiRen messages::internalError(aResp->res); 3718a3316fc6SZhikuiRen return; 3719a3316fc6SZhikuiRen } 3720a3316fc6SZhikuiRen 3721a3316fc6SZhikuiRen // skip the empty postcode boots 3722a3316fc6SZhikuiRen if (postcode.empty()) 3723a3316fc6SZhikuiRen { 3724a3316fc6SZhikuiRen return; 3725a3316fc6SZhikuiRen } 3726a3316fc6SZhikuiRen 3727a3316fc6SZhikuiRen fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex); 3728a3316fc6SZhikuiRen 3729a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = 3730a3316fc6SZhikuiRen aResp->res.jsonValue["Members"].size(); 3731a3316fc6SZhikuiRen }, 373215124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 373315124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3734a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3735a3316fc6SZhikuiRen bootIndex); 3736a3316fc6SZhikuiRen } 3737a3316fc6SZhikuiRen 37388d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3739a3316fc6SZhikuiRen const uint16_t bootIndex, 3740a3316fc6SZhikuiRen const uint16_t bootCount, 37413648c8beSEd Tanous const uint64_t entryCount, size_t skip, 37423648c8beSEd Tanous size_t top) 3743a3316fc6SZhikuiRen { 3744a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3745a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 3746a3316fc6SZhikuiRen top](const boost::system::error_code ec, 37476c9a279eSManojkiran Eda const boost::container::flat_map< 37486c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37496c9a279eSManojkiran Eda postcode) { 3750a3316fc6SZhikuiRen if (ec) 3751a3316fc6SZhikuiRen { 3752a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3753a3316fc6SZhikuiRen messages::internalError(aResp->res); 3754a3316fc6SZhikuiRen return; 3755a3316fc6SZhikuiRen } 3756a3316fc6SZhikuiRen 3757a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3758a3316fc6SZhikuiRen if (!postcode.empty()) 3759a3316fc6SZhikuiRen { 3760a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 37613648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3762a3316fc6SZhikuiRen { 37633648c8beSEd Tanous uint64_t thisBootSkip = 37643648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 37653648c8beSEd Tanous entryCount; 3766a3316fc6SZhikuiRen uint64_t thisBootTop = 37673648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 37683648c8beSEd Tanous entryCount; 3769a3316fc6SZhikuiRen 3770002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3771002d39b4SEd Tanous thisBootTop); 3772a3316fc6SZhikuiRen } 3773a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3774a3316fc6SZhikuiRen } 3775a3316fc6SZhikuiRen 3776a3316fc6SZhikuiRen // continue to previous bootIndex 3777a3316fc6SZhikuiRen if (bootIndex < bootCount) 3778a3316fc6SZhikuiRen { 3779a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3780a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3781a3316fc6SZhikuiRen } 378281584abeSJiaqing Zhao else if (skip + top < endCount) 3783a3316fc6SZhikuiRen { 3784a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 37850fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3786a3316fc6SZhikuiRen std::to_string(skip + top); 3787a3316fc6SZhikuiRen } 3788a3316fc6SZhikuiRen }, 378915124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 379015124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3791a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3792a3316fc6SZhikuiRen bootIndex); 3793a3316fc6SZhikuiRen } 3794a3316fc6SZhikuiRen 37958d1b46d7Szhanghch05 static void 37968d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 37973648c8beSEd Tanous size_t skip, size_t top) 3798a3316fc6SZhikuiRen { 3799a3316fc6SZhikuiRen uint64_t entryCount = 0; 38001e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 38011e1e598dSJonathan Doman *crow::connections::systemBus, 38021e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 38031e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 38041e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 38051e1e598dSJonathan Doman [aResp, entryCount, skip, top](const boost::system::error_code ec, 38061e1e598dSJonathan Doman const uint16_t bootCount) { 3807a3316fc6SZhikuiRen if (ec) 3808a3316fc6SZhikuiRen { 3809a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3810a3316fc6SZhikuiRen messages::internalError(aResp->res); 3811a3316fc6SZhikuiRen return; 3812a3316fc6SZhikuiRen } 38131e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 38141e1e598dSJonathan Doman }); 3815a3316fc6SZhikuiRen } 3816a3316fc6SZhikuiRen 38177e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3818a3316fc6SZhikuiRen { 38197e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 382022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3821ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 38227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 382345ca1b86SEd Tanous [&app](const crow::Request& req, 382422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 382522d268cbSEd Tanous const std::string& systemName) { 3826c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3827c937d2bfSEd Tanous .canDelegateTop = true, 3828c937d2bfSEd Tanous .canDelegateSkip = true, 3829c937d2bfSEd Tanous }; 3830c937d2bfSEd Tanous query_param::Query delegatedQuery; 3831c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 38323ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 383345ca1b86SEd Tanous { 383445ca1b86SEd Tanous return; 383545ca1b86SEd Tanous } 383622d268cbSEd Tanous 383722d268cbSEd Tanous if (systemName != "system") 383822d268cbSEd Tanous { 383922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 384022d268cbSEd Tanous systemName); 384122d268cbSEd Tanous ; 384222d268cbSEd Tanous return; 384322d268cbSEd Tanous } 3844a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3845a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3846a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3847a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3848a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3849a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3850a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3851a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3852a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 38533648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 38545143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 38553648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 38567e860f15SJohn Edward Broadbent }); 3857a3316fc6SZhikuiRen } 3858a3316fc6SZhikuiRen 3859647b3cdcSGeorge Liu /** 3860647b3cdcSGeorge Liu * @brief Parse post code ID and get the current value and index value 3861647b3cdcSGeorge Liu * eg: postCodeID=B1-2, currentValue=1, index=2 3862647b3cdcSGeorge Liu * 3863647b3cdcSGeorge Liu * @param[in] postCodeID Post Code ID 3864647b3cdcSGeorge Liu * @param[out] currentValue Current value 3865647b3cdcSGeorge Liu * @param[out] index Index value 3866647b3cdcSGeorge Liu * 3867647b3cdcSGeorge Liu * @return bool true if the parsing is successful, false the parsing fails 3868647b3cdcSGeorge Liu */ 3869647b3cdcSGeorge Liu inline static bool parsePostCode(const std::string& postCodeID, 3870647b3cdcSGeorge Liu uint64_t& currentValue, uint16_t& index) 3871647b3cdcSGeorge Liu { 3872647b3cdcSGeorge Liu std::vector<std::string> split; 3873647b3cdcSGeorge Liu boost::algorithm::split(split, postCodeID, boost::is_any_of("-")); 3874647b3cdcSGeorge Liu if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 3875647b3cdcSGeorge Liu { 3876647b3cdcSGeorge Liu return false; 3877647b3cdcSGeorge Liu } 3878647b3cdcSGeorge Liu 3879ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3880647b3cdcSGeorge Liu const char* start = split[0].data() + 1; 3881ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3882647b3cdcSGeorge Liu const char* end = split[0].data() + split[0].size(); 3883647b3cdcSGeorge Liu auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 3884647b3cdcSGeorge Liu 3885647b3cdcSGeorge Liu if (ptrIndex != end || ecIndex != std::errc()) 3886647b3cdcSGeorge Liu { 3887647b3cdcSGeorge Liu return false; 3888647b3cdcSGeorge Liu } 3889647b3cdcSGeorge Liu 3890647b3cdcSGeorge Liu start = split[1].data(); 3891ca45aa3cSEd Tanous 3892ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3893647b3cdcSGeorge Liu end = split[1].data() + split[1].size(); 3894647b3cdcSGeorge Liu auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 3895647b3cdcSGeorge Liu 3896517d9a58STony Lee return ptrValue == end && ecValue == std::errc(); 3897647b3cdcSGeorge Liu } 3898647b3cdcSGeorge Liu 3899647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3900647b3cdcSGeorge Liu { 39010fda0f12SGeorge Liu BMCWEB_ROUTE( 39020fda0f12SGeorge Liu app, 390322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3904647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3905647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 390645ca1b86SEd Tanous [&app](const crow::Request& req, 3907647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 390822d268cbSEd Tanous const std::string& systemName, 3909647b3cdcSGeorge Liu const std::string& postCodeID) { 39103ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 391145ca1b86SEd Tanous { 391245ca1b86SEd Tanous return; 391345ca1b86SEd Tanous } 391499351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 391599351cd8SEd Tanous req.getHeaderValue("Accept"), 39164a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3917647b3cdcSGeorge Liu { 3918002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3919647b3cdcSGeorge Liu return; 3920647b3cdcSGeorge Liu } 392122d268cbSEd Tanous if (systemName != "system") 392222d268cbSEd Tanous { 392322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 392422d268cbSEd Tanous systemName); 392522d268cbSEd Tanous ; 392622d268cbSEd Tanous return; 392722d268cbSEd Tanous } 3928647b3cdcSGeorge Liu 3929647b3cdcSGeorge Liu uint64_t currentValue = 0; 3930647b3cdcSGeorge Liu uint16_t index = 0; 3931647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3932647b3cdcSGeorge Liu { 3933002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3934647b3cdcSGeorge Liu return; 3935647b3cdcSGeorge Liu } 3936647b3cdcSGeorge Liu 3937647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3938647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 3939647b3cdcSGeorge Liu const boost::system::error_code ec, 3940002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 3941002d39b4SEd Tanous postcodes) { 3942647b3cdcSGeorge Liu if (ec.value() == EBADR) 3943647b3cdcSGeorge Liu { 3944002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3945002d39b4SEd Tanous postCodeID); 3946647b3cdcSGeorge Liu return; 3947647b3cdcSGeorge Liu } 3948647b3cdcSGeorge Liu if (ec) 3949647b3cdcSGeorge Liu { 3950647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3951647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 3952647b3cdcSGeorge Liu return; 3953647b3cdcSGeorge Liu } 3954647b3cdcSGeorge Liu 3955647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 3956002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 3957647b3cdcSGeorge Liu { 3958647b3cdcSGeorge Liu BMCWEB_LOG_ERROR << "Wrong currentValue value"; 3959002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3960002d39b4SEd Tanous postCodeID); 3961647b3cdcSGeorge Liu return; 3962647b3cdcSGeorge Liu } 3963647b3cdcSGeorge Liu 39649eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 396546ff87baSEd Tanous if (c.empty()) 3966647b3cdcSGeorge Liu { 3967647b3cdcSGeorge Liu BMCWEB_LOG_INFO << "No found post code data"; 3968002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3969002d39b4SEd Tanous postCodeID); 3970647b3cdcSGeorge Liu return; 3971647b3cdcSGeorge Liu } 397246ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 397346ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 397446ff87baSEd Tanous std::string_view strData(d, c.size()); 3975647b3cdcSGeorge Liu 3976d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 3977647b3cdcSGeorge Liu "application/octet-stream"); 3978d9f6c621SEd Tanous asyncResp->res.addHeader( 3979d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 3980002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 3981647b3cdcSGeorge Liu }, 3982647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 3983647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 3984002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 3985647b3cdcSGeorge Liu }); 3986647b3cdcSGeorge Liu } 3987647b3cdcSGeorge Liu 39887e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 3989a3316fc6SZhikuiRen { 39907e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 399122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 3992ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 39937e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 399445ca1b86SEd Tanous [&app](const crow::Request& req, 39957e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 399622d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 39973ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 399845ca1b86SEd Tanous { 399945ca1b86SEd Tanous return; 400045ca1b86SEd Tanous } 400122d268cbSEd Tanous if (systemName != "system") 400222d268cbSEd Tanous { 400322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 400422d268cbSEd Tanous systemName); 400522d268cbSEd Tanous return; 400622d268cbSEd Tanous } 400722d268cbSEd Tanous 4008647b3cdcSGeorge Liu uint16_t bootIndex = 0; 4009647b3cdcSGeorge Liu uint64_t codeIndex = 0; 4010647b3cdcSGeorge Liu if (!parsePostCode(targetID, codeIndex, bootIndex)) 4011a3316fc6SZhikuiRen { 4012a3316fc6SZhikuiRen // Requested ID was not found 40139db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 4014a3316fc6SZhikuiRen return; 4015a3316fc6SZhikuiRen } 4016a3316fc6SZhikuiRen if (bootIndex == 0 || codeIndex == 0) 4017a3316fc6SZhikuiRen { 4018a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string " 40197e860f15SJohn Edward Broadbent << targetID; 4020a3316fc6SZhikuiRen } 4021a3316fc6SZhikuiRen 40229c11a172SVijay Lobo asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4023a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 40240fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4025a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4026a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4027a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4028a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4029a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 4030a3316fc6SZhikuiRen 4031a3316fc6SZhikuiRen getPostCodeForEntry(asyncResp, bootIndex, codeIndex); 40327e860f15SJohn Edward Broadbent }); 4033a3316fc6SZhikuiRen } 4034a3316fc6SZhikuiRen 40351da66f75SEd Tanous } // namespace redfish 4036