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> 27400fd1fbSAdriana Kobylak #include <unistd.h> 28e1f26343SJason M. Bills 297e860f15SJohn Edward Broadbent #include <app.hpp> 309896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 3111ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 32400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 334851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 3407c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 351da66f75SEd Tanous #include <boost/container/flat_map.hpp> 361ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 37168e20c1SEd Tanous #include <dbus_utility.hpp> 38cb92c03bSAndrew Geissler #include <error_messages.hpp> 3945ca1b86SEd Tanous #include <query.hpp> 40ed398213SEd Tanous #include <registries/privilege_registry.hpp> 41d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 42d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 43d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp> 442b82937eSEd Tanous #include <utils/time_utils.hpp> 451214b7e7SGunnar Mills 46647b3cdcSGeorge Liu #include <charconv> 474418c7f0SJames Feist #include <filesystem> 4875710de2SXiaochao Ma #include <optional> 4926702d01SEd Tanous #include <span> 50cd225da8SJason M. Bills #include <string_view> 51abf2add6SEd Tanous #include <variant> 521da66f75SEd Tanous 531da66f75SEd Tanous namespace redfish 541da66f75SEd Tanous { 551da66f75SEd Tanous 565b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump"; 575b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump"; 585b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump"; 595b61b5e8SJason M. Bills constexpr char const* deleteAllInterface = 605b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 615b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface = 62424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 636eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface = 646eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 651da66f75SEd Tanous 66fffb8c1fSEd Tanous namespace registries 674851d45dSJason M. Bills { 6826702d01SEd Tanous static const Message* 6926702d01SEd Tanous getMessageFromRegistry(const std::string& messageKey, 7026702d01SEd Tanous const std::span<const MessageEntry> registry) 714851d45dSJason M. Bills { 72002d39b4SEd Tanous std::span<const MessageEntry>::iterator messageIt = 73002d39b4SEd Tanous std::find_if(registry.begin(), registry.end(), 744851d45dSJason M. Bills [&messageKey](const MessageEntry& messageEntry) { 75e662eae8SEd Tanous return std::strcmp(messageEntry.first, messageKey.c_str()) == 0; 764851d45dSJason M. Bills }); 7726702d01SEd Tanous if (messageIt != registry.end()) 784851d45dSJason M. Bills { 794851d45dSJason M. Bills return &messageIt->second; 804851d45dSJason M. Bills } 814851d45dSJason M. Bills 824851d45dSJason M. Bills return nullptr; 834851d45dSJason M. Bills } 844851d45dSJason M. Bills 854851d45dSJason M. Bills static const Message* getMessage(const std::string_view& messageID) 864851d45dSJason M. Bills { 874851d45dSJason M. Bills // Redfish MessageIds are in the form 884851d45dSJason M. Bills // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find 894851d45dSJason M. Bills // the right Message 904851d45dSJason M. Bills std::vector<std::string> fields; 914851d45dSJason M. Bills fields.reserve(4); 924851d45dSJason M. Bills boost::split(fields, messageID, boost::is_any_of(".")); 9302cad96eSEd Tanous const std::string& registryName = fields[0]; 9402cad96eSEd Tanous const std::string& messageKey = fields[3]; 954851d45dSJason M. Bills 964851d45dSJason M. Bills // Find the right registry and check it for the MessageKey 974851d45dSJason M. Bills if (std::string(base::header.registryPrefix) == registryName) 984851d45dSJason M. Bills { 994851d45dSJason M. Bills return getMessageFromRegistry( 10026702d01SEd Tanous messageKey, std::span<const MessageEntry>(base::registry)); 1014851d45dSJason M. Bills } 1024851d45dSJason M. Bills if (std::string(openbmc::header.registryPrefix) == registryName) 1034851d45dSJason M. Bills { 1044851d45dSJason M. Bills return getMessageFromRegistry( 10526702d01SEd Tanous messageKey, std::span<const MessageEntry>(openbmc::registry)); 1064851d45dSJason M. Bills } 1074851d45dSJason M. Bills return nullptr; 1084851d45dSJason M. Bills } 109fffb8c1fSEd Tanous } // namespace registries 1104851d45dSJason M. Bills 111f6150403SJames Feist namespace fs = std::filesystem; 1121da66f75SEd Tanous 113cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 114cb92c03bSAndrew Geissler { 115d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 116d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 117d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 118d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 119cb92c03bSAndrew Geissler { 120cb92c03bSAndrew Geissler return "Critical"; 121cb92c03bSAndrew Geissler } 1223174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 123d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 124d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 125cb92c03bSAndrew Geissler { 126cb92c03bSAndrew Geissler return "OK"; 127cb92c03bSAndrew Geissler } 1283174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 129cb92c03bSAndrew Geissler { 130cb92c03bSAndrew Geissler return "Warning"; 131cb92c03bSAndrew Geissler } 132cb92c03bSAndrew Geissler return ""; 133cb92c03bSAndrew Geissler } 134cb92c03bSAndrew Geissler 1357e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 13639e77504SEd Tanous const std::string_view& field, 13739e77504SEd Tanous std::string_view& contents) 13816428a1aSJason M. Bills { 13916428a1aSJason M. Bills const char* data = nullptr; 14016428a1aSJason M. Bills size_t length = 0; 14116428a1aSJason M. Bills int ret = 0; 14216428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14346ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 14446ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 14546ff87baSEd Tanous 14646ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 14716428a1aSJason M. Bills if (ret < 0) 14816428a1aSJason M. Bills { 14916428a1aSJason M. Bills return ret; 15016428a1aSJason M. Bills } 15139e77504SEd Tanous contents = std::string_view(data, length); 15216428a1aSJason M. Bills // Only use the content after the "=" character. 15381ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 15416428a1aSJason M. Bills return ret; 15516428a1aSJason M. Bills } 15616428a1aSJason M. Bills 1577e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 1587e860f15SJohn Edward Broadbent const std::string_view& field, 1597e860f15SJohn Edward Broadbent const int& base, long int& contents) 16016428a1aSJason M. Bills { 16116428a1aSJason M. Bills int ret = 0; 16239e77504SEd Tanous std::string_view metadata; 16316428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 16416428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 16516428a1aSJason M. Bills if (ret < 0) 16616428a1aSJason M. Bills { 16716428a1aSJason M. Bills return ret; 16816428a1aSJason M. Bills } 169b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 17016428a1aSJason M. Bills return ret; 17116428a1aSJason M. Bills } 17216428a1aSJason M. Bills 1737e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1747e860f15SJohn Edward Broadbent std::string& entryTimestamp) 175a3316fc6SZhikuiRen { 176a3316fc6SZhikuiRen int ret = 0; 177a3316fc6SZhikuiRen uint64_t timestamp = 0; 178a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 179a3316fc6SZhikuiRen if (ret < 0) 180a3316fc6SZhikuiRen { 181a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 182a3316fc6SZhikuiRen << strerror(-ret); 183a3316fc6SZhikuiRen return false; 184a3316fc6SZhikuiRen } 1852b82937eSEd Tanous entryTimestamp = 1862b82937eSEd Tanous redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000); 1879c620e21SAsmitha Karunanithi return true; 188a3316fc6SZhikuiRen } 18950b8a43aSEd Tanous 1907e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 191e85d6b16SJason M. Bills const bool firstEntry = true) 19216428a1aSJason M. Bills { 19316428a1aSJason M. Bills int ret = 0; 19416428a1aSJason M. Bills static uint64_t prevTs = 0; 19516428a1aSJason M. Bills static int index = 0; 196e85d6b16SJason M. Bills if (firstEntry) 197e85d6b16SJason M. Bills { 198e85d6b16SJason M. Bills prevTs = 0; 199e85d6b16SJason M. Bills } 200e85d6b16SJason M. Bills 20116428a1aSJason M. Bills // Get the entry timestamp 20216428a1aSJason M. Bills uint64_t curTs = 0; 20316428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 20416428a1aSJason M. Bills if (ret < 0) 20516428a1aSJason M. Bills { 20616428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 20716428a1aSJason M. Bills << strerror(-ret); 20816428a1aSJason M. Bills return false; 20916428a1aSJason M. Bills } 21016428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 21116428a1aSJason M. Bills if (curTs == prevTs) 21216428a1aSJason M. Bills { 21316428a1aSJason M. Bills index++; 21416428a1aSJason M. Bills } 21516428a1aSJason M. Bills else 21616428a1aSJason M. Bills { 21716428a1aSJason M. Bills // Otherwise, reset it 21816428a1aSJason M. Bills index = 0; 21916428a1aSJason M. Bills } 22016428a1aSJason M. Bills // Save the timestamp 22116428a1aSJason M. Bills prevTs = curTs; 22216428a1aSJason M. Bills 22316428a1aSJason M. Bills entryID = std::to_string(curTs); 22416428a1aSJason M. Bills if (index > 0) 22516428a1aSJason M. Bills { 22616428a1aSJason M. Bills entryID += "_" + std::to_string(index); 22716428a1aSJason M. Bills } 22816428a1aSJason M. Bills return true; 22916428a1aSJason M. Bills } 23016428a1aSJason M. Bills 231e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 232e85d6b16SJason M. Bills const bool firstEntry = true) 23395820184SJason M. Bills { 234271584abSEd Tanous static time_t prevTs = 0; 23595820184SJason M. Bills static int index = 0; 236e85d6b16SJason M. Bills if (firstEntry) 237e85d6b16SJason M. Bills { 238e85d6b16SJason M. Bills prevTs = 0; 239e85d6b16SJason M. Bills } 240e85d6b16SJason M. Bills 24195820184SJason M. Bills // Get the entry timestamp 242271584abSEd Tanous std::time_t curTs = 0; 24395820184SJason M. Bills std::tm timeStruct = {}; 24495820184SJason M. Bills std::istringstream entryStream(logEntry); 24595820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 24695820184SJason M. Bills { 24795820184SJason M. Bills curTs = std::mktime(&timeStruct); 24895820184SJason M. Bills } 24995820184SJason M. Bills // If the timestamp isn't unique, increment the index 25095820184SJason M. Bills if (curTs == prevTs) 25195820184SJason M. Bills { 25295820184SJason M. Bills index++; 25395820184SJason M. Bills } 25495820184SJason M. Bills else 25595820184SJason M. Bills { 25695820184SJason M. Bills // Otherwise, reset it 25795820184SJason M. Bills index = 0; 25895820184SJason M. Bills } 25995820184SJason M. Bills // Save the timestamp 26095820184SJason M. Bills prevTs = curTs; 26195820184SJason M. Bills 26295820184SJason M. Bills entryID = std::to_string(curTs); 26395820184SJason M. Bills if (index > 0) 26495820184SJason M. Bills { 26595820184SJason M. Bills entryID += "_" + std::to_string(index); 26695820184SJason M. Bills } 26795820184SJason M. Bills return true; 26895820184SJason M. Bills } 26995820184SJason M. Bills 2707e860f15SJohn Edward Broadbent inline static bool 2718d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2728d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2738d1b46d7Szhanghch05 uint64_t& index) 27416428a1aSJason M. Bills { 27516428a1aSJason M. Bills if (entryID.empty()) 27616428a1aSJason M. Bills { 27716428a1aSJason M. Bills return false; 27816428a1aSJason M. Bills } 27916428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 28039e77504SEd Tanous std::string_view tsStr(entryID); 28116428a1aSJason M. Bills 28281ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 28371d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 28416428a1aSJason M. Bills { 28516428a1aSJason M. Bills // Timestamp has an index 28616428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 28739e77504SEd Tanous std::string_view indexStr(entryID); 28816428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 289c0bd5e4bSEd Tanous auto [ptr, ec] = std::from_chars( 290c0bd5e4bSEd Tanous indexStr.data(), indexStr.data() + indexStr.size(), index); 291c0bd5e4bSEd Tanous if (ec != std::errc()) 29216428a1aSJason M. Bills { 293*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 29416428a1aSJason M. Bills return false; 29516428a1aSJason M. Bills } 29616428a1aSJason M. Bills } 29716428a1aSJason M. Bills // Timestamp has no index 298c0bd5e4bSEd Tanous auto [ptr, ec] = 299c0bd5e4bSEd Tanous std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp); 300c0bd5e4bSEd Tanous if (ec != std::errc()) 30116428a1aSJason M. Bills { 302*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 30316428a1aSJason M. Bills return false; 30416428a1aSJason M. Bills } 30516428a1aSJason M. Bills return true; 30616428a1aSJason M. Bills } 30716428a1aSJason M. Bills 30895820184SJason M. Bills static bool 30995820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 31095820184SJason M. Bills { 31195820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 31295820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 31395820184SJason M. Bills 31495820184SJason M. Bills // Loop through the directory looking for redfish log files 31595820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 31695820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 31795820184SJason M. Bills { 31895820184SJason M. Bills // If we find a redfish log file, save the path 31995820184SJason M. Bills std::string filename = dirEnt.path().filename(); 32011ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 32195820184SJason M. Bills { 32295820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 32395820184SJason M. Bills } 32495820184SJason M. Bills } 32595820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 32695820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 32795820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 32895820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 32995820184SJason M. Bills 33095820184SJason M. Bills return !redfishLogFiles.empty(); 33195820184SJason M. Bills } 33295820184SJason M. Bills 333aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3342d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 335c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 336aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 337aefe3786SClaire Weinan { 338aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 339aefe3786SClaire Weinan { 340aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 341aefe3786SClaire Weinan { 342aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 343aefe3786SClaire Weinan { 344aefe3786SClaire Weinan if (propertyMap.first == "Status") 345aefe3786SClaire Weinan { 346aefe3786SClaire Weinan const auto* status = 347aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 348aefe3786SClaire Weinan if (status == nullptr) 349aefe3786SClaire Weinan { 350aefe3786SClaire Weinan messages::internalError(asyncResp->res); 351aefe3786SClaire Weinan break; 352aefe3786SClaire Weinan } 353aefe3786SClaire Weinan dumpStatus = *status; 354aefe3786SClaire Weinan } 355aefe3786SClaire Weinan } 356aefe3786SClaire Weinan } 357aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 358aefe3786SClaire Weinan { 359aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 360aefe3786SClaire Weinan { 361aefe3786SClaire Weinan if (propertyMap.first == "Size") 362aefe3786SClaire Weinan { 363aefe3786SClaire Weinan const auto* sizePtr = 364aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 365aefe3786SClaire Weinan if (sizePtr == nullptr) 366aefe3786SClaire Weinan { 367aefe3786SClaire Weinan messages::internalError(asyncResp->res); 368aefe3786SClaire Weinan break; 369aefe3786SClaire Weinan } 370aefe3786SClaire Weinan size = *sizePtr; 371aefe3786SClaire Weinan break; 372aefe3786SClaire Weinan } 373aefe3786SClaire Weinan } 374aefe3786SClaire Weinan } 375aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 376aefe3786SClaire Weinan { 377aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 378aefe3786SClaire Weinan { 379aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 380aefe3786SClaire Weinan { 381aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 382aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 383aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan messages::internalError(asyncResp->res); 386aefe3786SClaire Weinan break; 387aefe3786SClaire Weinan } 388c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 389aefe3786SClaire Weinan break; 390aefe3786SClaire Weinan } 391aefe3786SClaire Weinan } 392aefe3786SClaire Weinan } 393aefe3786SClaire Weinan } 394aefe3786SClaire Weinan } 395aefe3786SClaire Weinan 39621ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 397fdd26906SClaire Weinan { 398fdd26906SClaire Weinan std::string entriesPath; 399fdd26906SClaire Weinan 400fdd26906SClaire Weinan if (dumpType == "BMC") 401fdd26906SClaire Weinan { 402fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 403fdd26906SClaire Weinan } 404fdd26906SClaire Weinan else if (dumpType == "FaultLog") 405fdd26906SClaire Weinan { 406fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 407fdd26906SClaire Weinan } 408fdd26906SClaire Weinan else if (dumpType == "System") 409fdd26906SClaire Weinan { 410fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 411fdd26906SClaire Weinan } 412fdd26906SClaire Weinan else 413fdd26906SClaire Weinan { 414fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 415fdd26906SClaire Weinan << dumpType; 416fdd26906SClaire Weinan } 417fdd26906SClaire Weinan 418fdd26906SClaire Weinan // Returns empty string on error 419fdd26906SClaire Weinan return entriesPath; 420fdd26906SClaire Weinan } 421fdd26906SClaire Weinan 4228d1b46d7Szhanghch05 inline void 4238d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4245cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4255cb1dd27SAsmitha Karunanithi { 426fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 427fdd26906SClaire Weinan if (entriesPath.empty()) 4285cb1dd27SAsmitha Karunanithi { 4295cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4305cb1dd27SAsmitha Karunanithi return; 4315cb1dd27SAsmitha Karunanithi } 4325cb1dd27SAsmitha Karunanithi 4335cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 434fdd26906SClaire Weinan [asyncResp, entriesPath, 435711ac7a9SEd Tanous dumpType](const boost::system::error_code ec, 436711ac7a9SEd Tanous dbus::utility::ManagedObjectType& resp) { 4375cb1dd27SAsmitha Karunanithi if (ec) 4385cb1dd27SAsmitha Karunanithi { 4395cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4405cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4415cb1dd27SAsmitha Karunanithi return; 4425cb1dd27SAsmitha Karunanithi } 4435cb1dd27SAsmitha Karunanithi 444fdd26906SClaire Weinan // Remove ending slash 445fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 446fdd26906SClaire Weinan if (!odataIdStr.empty()) 447fdd26906SClaire Weinan { 448fdd26906SClaire Weinan odataIdStr.pop_back(); 449fdd26906SClaire Weinan } 450fdd26906SClaire Weinan 451fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 452fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 453fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 454fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 455fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = 456fdd26906SClaire Weinan "Collection of " + dumpType + " Dump Entries"; 457fdd26906SClaire Weinan 4585cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4595cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 460b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 461b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 462002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 4635cb1dd27SAsmitha Karunanithi 464002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 465002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 466002d39b4SEd Tanous r.first.filename()); 467565dfb6fSClaire Weinan }); 468565dfb6fSClaire Weinan 4695cb1dd27SAsmitha Karunanithi for (auto& object : resp) 4705cb1dd27SAsmitha Karunanithi { 471b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 4725cb1dd27SAsmitha Karunanithi { 4735cb1dd27SAsmitha Karunanithi continue; 4745cb1dd27SAsmitha Karunanithi } 475c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4765cb1dd27SAsmitha Karunanithi uint64_t size = 0; 47735440d18SAsmitha Karunanithi std::string dumpStatus; 478433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 4792dfd18efSEd Tanous 4802dfd18efSEd Tanous std::string entryID = object.first.filename(); 4812dfd18efSEd Tanous if (entryID.empty()) 4825cb1dd27SAsmitha Karunanithi { 4835cb1dd27SAsmitha Karunanithi continue; 4845cb1dd27SAsmitha Karunanithi } 4855cb1dd27SAsmitha Karunanithi 486c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 487aefe3786SClaire Weinan asyncResp); 4885cb1dd27SAsmitha Karunanithi 4890fda0f12SGeorge Liu if (dumpStatus != 4900fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 49135440d18SAsmitha Karunanithi !dumpStatus.empty()) 49235440d18SAsmitha Karunanithi { 49335440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 49435440d18SAsmitha Karunanithi continue; 49535440d18SAsmitha Karunanithi } 49635440d18SAsmitha Karunanithi 4979c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 498fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 4995cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5005cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5015cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 5025cb1dd27SAsmitha Karunanithi 5035cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5045cb1dd27SAsmitha Karunanithi { 505c6fecdabSClaire Weinan thisEntry["Created"] = redfish::time_utils::getDateTimeUint( 506c6fecdabSClaire Weinan timestampUs / 1000 / 1000); 507d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 508d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 509fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 510fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5115cb1dd27SAsmitha Karunanithi } 512c6fecdabSClaire Weinan else if (dumpType == "FaultLog") 513c6fecdabSClaire Weinan { 514c6fecdabSClaire Weinan thisEntry["Created"] = 515c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 516c6fecdabSClaire Weinan } 5175cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5185cb1dd27SAsmitha Karunanithi { 519c6fecdabSClaire Weinan thisEntry["Created"] = redfish::time_utils::getDateTimeUint( 520c6fecdabSClaire Weinan timestampUs / 1000 / 1000); 521d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 522d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 523d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 524fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 525fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5265cb1dd27SAsmitha Karunanithi } 52735440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5285cb1dd27SAsmitha Karunanithi } 529002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5305cb1dd27SAsmitha Karunanithi }, 5315cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5325cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 5335cb1dd27SAsmitha Karunanithi } 5345cb1dd27SAsmitha Karunanithi 5358d1b46d7Szhanghch05 inline void 536c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5378d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5385cb1dd27SAsmitha Karunanithi { 539fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 540fdd26906SClaire Weinan if (entriesPath.empty()) 5415cb1dd27SAsmitha Karunanithi { 5425cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5435cb1dd27SAsmitha Karunanithi return; 5445cb1dd27SAsmitha Karunanithi } 5455cb1dd27SAsmitha Karunanithi 5465cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 547fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 548fdd26906SClaire Weinan entriesPath](const boost::system::error_code ec, 54902cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5505cb1dd27SAsmitha Karunanithi if (ec) 5515cb1dd27SAsmitha Karunanithi { 5525cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5535cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5545cb1dd27SAsmitha Karunanithi return; 5555cb1dd27SAsmitha Karunanithi } 5565cb1dd27SAsmitha Karunanithi 557b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 558b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 559b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 560002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 561b47452b2SAsmitha Karunanithi 5629eb808c1SEd Tanous for (const auto& objectPath : resp) 5635cb1dd27SAsmitha Karunanithi { 564b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 5655cb1dd27SAsmitha Karunanithi { 5665cb1dd27SAsmitha Karunanithi continue; 5675cb1dd27SAsmitha Karunanithi } 5685cb1dd27SAsmitha Karunanithi 5695cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 570c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5715cb1dd27SAsmitha Karunanithi uint64_t size = 0; 57235440d18SAsmitha Karunanithi std::string dumpStatus; 5735cb1dd27SAsmitha Karunanithi 574aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 575c6fecdabSClaire Weinan timestampUs, asyncResp); 5765cb1dd27SAsmitha Karunanithi 5770fda0f12SGeorge Liu if (dumpStatus != 5780fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 57935440d18SAsmitha Karunanithi !dumpStatus.empty()) 58035440d18SAsmitha Karunanithi { 58135440d18SAsmitha Karunanithi // Dump status is not Complete 58235440d18SAsmitha Karunanithi // return not found until status is changed to Completed 583d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 584d1bde9e5SKrzysztof Grobelny entryID); 58535440d18SAsmitha Karunanithi return; 58635440d18SAsmitha Karunanithi } 58735440d18SAsmitha Karunanithi 5885cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 5899c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 590fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 5915cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 5925cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 5935cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 5945cb1dd27SAsmitha Karunanithi 5955cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5965cb1dd27SAsmitha Karunanithi { 597c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 598c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUint(timestampUs / 1000 / 599c6fecdabSClaire Weinan 1000); 600d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 601d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 602fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 603fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6045cb1dd27SAsmitha Karunanithi } 605c6fecdabSClaire Weinan else if (dumpType == "FaultLog") 606c6fecdabSClaire Weinan { 607c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 608c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 609c6fecdabSClaire Weinan } 6105cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6115cb1dd27SAsmitha Karunanithi { 612c6fecdabSClaire Weinan asyncResp->res.jsonValue["Created"] = 613c6fecdabSClaire Weinan redfish::time_utils::getDateTimeUint(timestampUs / 1000 / 614c6fecdabSClaire Weinan 1000); 615d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 616002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 617d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 618fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 619fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6205cb1dd27SAsmitha Karunanithi } 6215cb1dd27SAsmitha Karunanithi } 622e05aec50SEd Tanous if (!foundDumpEntry) 623b47452b2SAsmitha Karunanithi { 624b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 625b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 626b47452b2SAsmitha Karunanithi return; 627b47452b2SAsmitha Karunanithi } 6285cb1dd27SAsmitha Karunanithi }, 6295cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6305cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6315cb1dd27SAsmitha Karunanithi } 6325cb1dd27SAsmitha Karunanithi 6338d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6349878256fSStanley Chu const std::string& entryID, 635b47452b2SAsmitha Karunanithi const std::string& dumpType) 6365cb1dd27SAsmitha Karunanithi { 637002d39b4SEd Tanous auto respHandler = 638002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 6395cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6405cb1dd27SAsmitha Karunanithi if (ec) 6415cb1dd27SAsmitha Karunanithi { 6423de8d8baSGeorge Liu if (ec.value() == EBADR) 6433de8d8baSGeorge Liu { 6443de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6453de8d8baSGeorge Liu return; 6463de8d8baSGeorge Liu } 6475cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 648fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6495cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6505cb1dd27SAsmitha Karunanithi return; 6515cb1dd27SAsmitha Karunanithi } 6525cb1dd27SAsmitha Karunanithi }; 6535cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6545cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 655b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 656b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 657b47452b2SAsmitha Karunanithi entryID, 6585cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 6595cb1dd27SAsmitha Karunanithi } 6605cb1dd27SAsmitha Karunanithi 6618d1b46d7Szhanghch05 inline void 66298be3e39SEd Tanous createDumpTaskCallback(task::Payload&& payload, 6638d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6648d1b46d7Szhanghch05 const uint32_t& dumpId, const std::string& dumpPath, 665a43be80fSAsmitha Karunanithi const std::string& dumpType) 666a43be80fSAsmitha Karunanithi { 667a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 66859d494eeSPatrick Williams [dumpId, dumpPath, 66959d494eeSPatrick Williams dumpType](boost::system::error_code err, sdbusplus::message_t& m, 670a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 671cb13a392SEd Tanous if (err) 672cb13a392SEd Tanous { 6736145ed6fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Error in creating a dump"; 6746145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 6756145ed6fSAsmitha Karunanithi return task::completed; 676cb13a392SEd Tanous } 677b9d36b47SEd Tanous 678b9d36b47SEd Tanous dbus::utility::DBusInteracesMap interfacesList; 679a43be80fSAsmitha Karunanithi 680a43be80fSAsmitha Karunanithi sdbusplus::message::object_path objPath; 681a43be80fSAsmitha Karunanithi 682a43be80fSAsmitha Karunanithi m.read(objPath, interfacesList); 683a43be80fSAsmitha Karunanithi 684b47452b2SAsmitha Karunanithi if (objPath.str == 685b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 686b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + 687b47452b2SAsmitha Karunanithi "/entry/" + std::to_string(dumpId)) 688a43be80fSAsmitha Karunanithi { 689a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 690a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 691a43be80fSAsmitha Karunanithi 692a43be80fSAsmitha Karunanithi std::string headerLoc = 693a43be80fSAsmitha Karunanithi "Location: " + dumpPath + std::to_string(dumpId); 694002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 695a43be80fSAsmitha Karunanithi 696a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 697b47452b2SAsmitha Karunanithi return task::completed; 6986145ed6fSAsmitha Karunanithi } 699a43be80fSAsmitha Karunanithi return task::completed; 700a43be80fSAsmitha Karunanithi }, 7014978b63fSJason M. Bills "type='signal',interface='org.freedesktop.DBus.ObjectManager'," 702a43be80fSAsmitha Karunanithi "member='InterfacesAdded', " 703a43be80fSAsmitha Karunanithi "path='/xyz/openbmc_project/dump'"); 704a43be80fSAsmitha Karunanithi 705a43be80fSAsmitha Karunanithi task->startTimer(std::chrono::minutes(3)); 706a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 70798be3e39SEd Tanous task->payload.emplace(std::move(payload)); 708a43be80fSAsmitha Karunanithi } 709a43be80fSAsmitha Karunanithi 7108d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7118d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 712a43be80fSAsmitha Karunanithi { 713fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 714fdd26906SClaire Weinan if (dumpPath.empty()) 715a43be80fSAsmitha Karunanithi { 716a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 717a43be80fSAsmitha Karunanithi return; 718a43be80fSAsmitha Karunanithi } 719a43be80fSAsmitha Karunanithi 720a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 721a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 722a43be80fSAsmitha Karunanithi 72315ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 724a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 725a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 726a43be80fSAsmitha Karunanithi { 727a43be80fSAsmitha Karunanithi return; 728a43be80fSAsmitha Karunanithi } 729a43be80fSAsmitha Karunanithi 730a43be80fSAsmitha Karunanithi if (dumpType == "System") 731a43be80fSAsmitha Karunanithi { 732a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 733a43be80fSAsmitha Karunanithi { 7344978b63fSJason M. Bills BMCWEB_LOG_ERROR 7354978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 736a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 737a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 738a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 739a43be80fSAsmitha Karunanithi return; 740a43be80fSAsmitha Karunanithi } 7413174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 742a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 743a43be80fSAsmitha Karunanithi { 744a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 745ace85d60SEd Tanous messages::internalError(asyncResp->res); 746a43be80fSAsmitha Karunanithi return; 747a43be80fSAsmitha Karunanithi } 7485907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 749a43be80fSAsmitha Karunanithi } 750a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 751a43be80fSAsmitha Karunanithi { 752a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 753a43be80fSAsmitha Karunanithi { 7540fda0f12SGeorge Liu BMCWEB_LOG_ERROR 7550fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 756a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 757a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 758a43be80fSAsmitha Karunanithi return; 759a43be80fSAsmitha Karunanithi } 7603174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 761a43be80fSAsmitha Karunanithi { 762a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 763a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 764ace85d60SEd Tanous messages::internalError(asyncResp->res); 765a43be80fSAsmitha Karunanithi return; 766a43be80fSAsmitha Karunanithi } 7675907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 7685907571dSAsmitha Karunanithi } 7695907571dSAsmitha Karunanithi else 7705907571dSAsmitha Karunanithi { 7715907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 7725907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 7735907571dSAsmitha Karunanithi return; 774a43be80fSAsmitha Karunanithi } 775a43be80fSAsmitha Karunanithi 776a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 77798be3e39SEd Tanous [asyncResp, payload(task::Payload(req)), dumpPath, 77898be3e39SEd Tanous dumpType](const boost::system::error_code ec, 7795907571dSAsmitha Karunanithi const sdbusplus::message::message& msg, 78098be3e39SEd Tanous const uint32_t& dumpId) mutable { 781a43be80fSAsmitha Karunanithi if (ec) 782a43be80fSAsmitha Karunanithi { 783a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 7845907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 7855907571dSAsmitha Karunanithi if (dbusError == nullptr) 7865907571dSAsmitha Karunanithi { 7875907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 7885907571dSAsmitha Karunanithi return; 7895907571dSAsmitha Karunanithi } 7905907571dSAsmitha Karunanithi 7915907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 7925907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 7935907571dSAsmitha Karunanithi if (std::string_view( 7945907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 7955907571dSAsmitha Karunanithi dbusError->name) 7965907571dSAsmitha Karunanithi { 7975907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 7985907571dSAsmitha Karunanithi return; 7995907571dSAsmitha Karunanithi } 8005907571dSAsmitha Karunanithi if (std::string_view( 8015907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 8025907571dSAsmitha Karunanithi dbusError->name) 8035907571dSAsmitha Karunanithi { 8045907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 8055907571dSAsmitha Karunanithi return; 8065907571dSAsmitha Karunanithi } 8075907571dSAsmitha Karunanithi if (std::string_view( 8085907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 8095907571dSAsmitha Karunanithi dbusError->name) 8105907571dSAsmitha Karunanithi { 8115907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 8125907571dSAsmitha Karunanithi return; 8135907571dSAsmitha Karunanithi } 8145907571dSAsmitha Karunanithi // Other Dbus errors such as: 8155907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 8165907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 8175907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 8185907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 8195907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 8205907571dSAsmitha Karunanithi // back to the client. 821a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 822a43be80fSAsmitha Karunanithi return; 823a43be80fSAsmitha Karunanithi } 824a43be80fSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId; 825a43be80fSAsmitha Karunanithi 826002d39b4SEd Tanous createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath, 827002d39b4SEd Tanous dumpType); 828a43be80fSAsmitha Karunanithi }, 829b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 830b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 831b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 832a43be80fSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump"); 833a43be80fSAsmitha Karunanithi } 834a43be80fSAsmitha Karunanithi 8358d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8368d1b46d7Szhanghch05 const std::string& dumpType) 83780319af1SAsmitha Karunanithi { 838b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 839b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 8408d1b46d7Szhanghch05 84180319af1SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 842b9d36b47SEd Tanous [asyncResp, dumpType]( 843b9d36b47SEd Tanous const boost::system::error_code ec, 844b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 84580319af1SAsmitha Karunanithi if (ec) 84680319af1SAsmitha Karunanithi { 84780319af1SAsmitha Karunanithi BMCWEB_LOG_ERROR << "resp_handler got error " << ec; 84880319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 84980319af1SAsmitha Karunanithi return; 85080319af1SAsmitha Karunanithi } 85180319af1SAsmitha Karunanithi 85280319af1SAsmitha Karunanithi for (const std::string& path : subTreePaths) 85380319af1SAsmitha Karunanithi { 8542dfd18efSEd Tanous sdbusplus::message::object_path objPath(path); 8552dfd18efSEd Tanous std::string logID = objPath.filename(); 8562dfd18efSEd Tanous if (logID.empty()) 85780319af1SAsmitha Karunanithi { 8582dfd18efSEd Tanous continue; 85980319af1SAsmitha Karunanithi } 8602dfd18efSEd Tanous deleteDumpEntry(asyncResp, logID, dumpType); 86180319af1SAsmitha Karunanithi } 86280319af1SAsmitha Karunanithi }, 86380319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", 86480319af1SAsmitha Karunanithi "/xyz/openbmc_project/object_mapper", 86580319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 866b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, 867b47452b2SAsmitha Karunanithi std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." + 868b47452b2SAsmitha Karunanithi dumpType}); 86980319af1SAsmitha Karunanithi } 87080319af1SAsmitha Karunanithi 871b9d36b47SEd Tanous inline static void 872b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 873b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 874b9d36b47SEd Tanous std::string& logfile) 875043a0536SJohnathan Mantey { 876d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 877d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 878d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 879d1bde9e5SKrzysztof Grobelny 880d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 881d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 882d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 883d1bde9e5SKrzysztof Grobelny 884d1bde9e5SKrzysztof Grobelny if (!success) 885043a0536SJohnathan Mantey { 886d1bde9e5SKrzysztof Grobelny return; 887043a0536SJohnathan Mantey } 888d1bde9e5SKrzysztof Grobelny 889d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 890043a0536SJohnathan Mantey { 891d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 892d1bde9e5SKrzysztof Grobelny } 893d1bde9e5SKrzysztof Grobelny 894d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 895043a0536SJohnathan Mantey { 896d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 897043a0536SJohnathan Mantey } 898d1bde9e5SKrzysztof Grobelny 899d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 900043a0536SJohnathan Mantey { 901d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 902043a0536SJohnathan Mantey } 903043a0536SJohnathan Mantey } 904043a0536SJohnathan Mantey 905a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode"; 9067e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 9071da66f75SEd Tanous { 908c4bf6374SJason M. Bills /** 909c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 910c4bf6374SJason M. Bills */ 91122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 912ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 913002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 914002d39b4SEd Tanous [&app](const crow::Request& req, 91522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 91622d268cbSEd Tanous const std::string& systemName) { 9173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 918c4bf6374SJason M. Bills { 91945ca1b86SEd Tanous return; 92045ca1b86SEd Tanous } 92122d268cbSEd Tanous if (systemName != "system") 92222d268cbSEd Tanous { 92322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 92422d268cbSEd Tanous systemName); 92522d268cbSEd Tanous return; 92622d268cbSEd Tanous } 92722d268cbSEd Tanous 9287e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 9297e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 930c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 931c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 932c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 933029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 93445ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 935c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 936c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 937002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 938c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 9391476687dSEd Tanous nlohmann::json::object_t eventLog; 9401476687dSEd Tanous eventLog["@odata.id"] = 9411476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 9421476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 9435cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 9441476687dSEd Tanous nlohmann::json::object_t dumpLog; 945002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 9461476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 947c9bb6861Sraviteja-b #endif 948c9bb6861Sraviteja-b 949d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 9501476687dSEd Tanous nlohmann::json::object_t crashdump; 9511476687dSEd Tanous crashdump["@odata.id"] = 9521476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 9531476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 954d53dd41fSJason M. Bills #endif 955b7028ebfSSpencer Ku 956b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 9571476687dSEd Tanous nlohmann::json::object_t hostlogger; 9581476687dSEd Tanous hostlogger["@odata.id"] = 9591476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 9601476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 961b7028ebfSSpencer Ku #endif 962c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 963c4bf6374SJason M. Bills logServiceArray.size(); 964a3316fc6SZhikuiRen 965a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 96645ca1b86SEd Tanous [asyncResp](const boost::system::error_code ec, 967b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 968b9d36b47SEd Tanous subtreePath) { 969a3316fc6SZhikuiRen if (ec) 970a3316fc6SZhikuiRen { 971a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 972a3316fc6SZhikuiRen return; 973a3316fc6SZhikuiRen } 974a3316fc6SZhikuiRen 97555f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 976a3316fc6SZhikuiRen { 977a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 978a3316fc6SZhikuiRen { 97923a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 980a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 981613dabeaSEd Tanous nlohmann::json::object_t member; 982613dabeaSEd Tanous member["@odata.id"] = 983613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 984613dabeaSEd Tanous 985613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 986613dabeaSEd Tanous 98745ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 98823a21a1cSEd Tanous logServiceArrayLocal.size(); 989a3316fc6SZhikuiRen return; 990a3316fc6SZhikuiRen } 991a3316fc6SZhikuiRen } 992a3316fc6SZhikuiRen }, 993a3316fc6SZhikuiRen "xyz.openbmc_project.ObjectMapper", 994a3316fc6SZhikuiRen "/xyz/openbmc_project/object_mapper", 99545ca1b86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0, 99645ca1b86SEd Tanous std::array<const char*, 1>{postCodeIface}); 9977e860f15SJohn Edward Broadbent }); 998c4bf6374SJason M. Bills } 999c4bf6374SJason M. Bills 10007e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1001c4bf6374SJason M. Bills { 100222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1003ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1004002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1005002d39b4SEd Tanous [&app](const crow::Request& req, 100622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 100722d268cbSEd Tanous const std::string& systemName) { 10083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 100945ca1b86SEd Tanous { 101045ca1b86SEd Tanous return; 101145ca1b86SEd Tanous } 101222d268cbSEd Tanous if (systemName != "system") 101322d268cbSEd Tanous { 101422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 101522d268cbSEd Tanous systemName); 101622d268cbSEd Tanous return; 101722d268cbSEd Tanous } 1018c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1019029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1020c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1021c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1022c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1023002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1024c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1025c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 10267c8c4058STejas Patil 10277c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 10282b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 10297c8c4058STejas Patil 10307c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 10317c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 10327c8c4058STejas Patil redfishDateTimeOffset.second; 10337c8c4058STejas Patil 10341476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 10351476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1036e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1037e7d6c8b2SGunnar Mills 10380fda0f12SGeorge Liu {"target", 10390fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 10407e860f15SJohn Edward Broadbent }); 1041489640c6SJason M. Bills } 1042489640c6SJason M. Bills 10437e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1044489640c6SJason M. Bills { 10454978b63fSJason M. Bills BMCWEB_ROUTE( 10464978b63fSJason M. Bills app, 104722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1048432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 10497e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 105045ca1b86SEd Tanous [&app](const crow::Request& req, 105122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 105222d268cbSEd Tanous const std::string& systemName) { 10533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105445ca1b86SEd Tanous { 105545ca1b86SEd Tanous return; 105645ca1b86SEd Tanous } 105722d268cbSEd Tanous if (systemName != "system") 105822d268cbSEd Tanous { 105922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 106022d268cbSEd Tanous systemName); 106122d268cbSEd Tanous return; 106222d268cbSEd Tanous } 1063489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1064489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1065489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1066489640c6SJason M. Bills { 1067489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1068489640c6SJason M. Bills { 1069489640c6SJason M. Bills std::error_code ec; 1070489640c6SJason M. Bills std::filesystem::remove(file, ec); 1071489640c6SJason M. Bills } 1072489640c6SJason M. Bills } 1073489640c6SJason M. Bills 1074489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1075489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 1076489640c6SJason M. Bills [asyncResp](const boost::system::error_code ec) { 1077489640c6SJason M. Bills if (ec) 1078489640c6SJason M. Bills { 1079002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1080489640c6SJason M. Bills messages::internalError(asyncResp->res); 1081489640c6SJason M. Bills return; 1082489640c6SJason M. Bills } 1083489640c6SJason M. Bills 1084489640c6SJason M. Bills messages::success(asyncResp->res); 1085489640c6SJason M. Bills }, 1086489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1087002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1088002d39b4SEd Tanous "replace"); 10897e860f15SJohn Edward Broadbent }); 1090c4bf6374SJason M. Bills } 1091c4bf6374SJason M. Bills 1092ac992cdeSJason M. Bills enum class LogParseError 1093ac992cdeSJason M. Bills { 1094ac992cdeSJason M. Bills success, 1095ac992cdeSJason M. Bills parseFailed, 1096ac992cdeSJason M. Bills messageIdNotInRegistry, 1097ac992cdeSJason M. Bills }; 1098ac992cdeSJason M. Bills 1099ac992cdeSJason M. Bills static LogParseError 1100ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1101b5a76932SEd Tanous const std::string& logEntry, 1102de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1103c4bf6374SJason M. Bills { 110495820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1105cd225da8SJason M. Bills // First get the Timestamp 1106f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1107cd225da8SJason M. Bills if (space == std::string::npos) 110895820184SJason M. Bills { 1109ac992cdeSJason M. Bills return LogParseError::parseFailed; 111095820184SJason M. Bills } 1111cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1112cd225da8SJason M. Bills // Then get the log contents 1113f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1114cd225da8SJason M. Bills if (entryStart == std::string::npos) 1115cd225da8SJason M. Bills { 1116ac992cdeSJason M. Bills return LogParseError::parseFailed; 1117cd225da8SJason M. Bills } 1118cd225da8SJason M. Bills std::string_view entry(logEntry); 1119cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1120cd225da8SJason M. Bills // Use split to separate the entry into its fields 1121cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 1122cd225da8SJason M. Bills boost::split(logEntryFields, entry, boost::is_any_of(","), 1123cd225da8SJason M. Bills boost::token_compress_on); 1124cd225da8SJason M. Bills // We need at least a MessageId to be valid 112526f6976fSEd Tanous if (logEntryFields.empty()) 1126cd225da8SJason M. Bills { 1127ac992cdeSJason M. Bills return LogParseError::parseFailed; 1128cd225da8SJason M. Bills } 1129cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 113095820184SJason M. Bills 11314851d45dSJason M. Bills // Get the Message from the MessageRegistry 1132fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1133c4bf6374SJason M. Bills 113454417b02SSui Chen if (message == nullptr) 1135c4bf6374SJason M. Bills { 113654417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1137ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1138c4bf6374SJason M. Bills } 1139c4bf6374SJason M. Bills 114054417b02SSui Chen std::string msg = message->message; 114154417b02SSui Chen 114215a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 114326702d01SEd Tanous std::span<std::string> messageArgs; 114415a86ff6SJason M. Bills if (logEntryFields.size() > 1) 114515a86ff6SJason M. Bills { 114615a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 114715a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 114815a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 114915a86ff6SJason M. Bills if (!messageArgsStart.empty()) 115015a86ff6SJason M. Bills { 115115a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 115215a86ff6SJason M. Bills } 115315a86ff6SJason M. Bills 115423a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1155c4bf6374SJason M. Bills 11564851d45dSJason M. Bills // Fill the MessageArgs into the Message 115795820184SJason M. Bills int i = 0; 115895820184SJason M. Bills for (const std::string& messageArg : messageArgs) 11594851d45dSJason M. Bills { 116095820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 11614851d45dSJason M. Bills size_t argPos = msg.find(argStr); 11624851d45dSJason M. Bills if (argPos != std::string::npos) 11634851d45dSJason M. Bills { 116495820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 11654851d45dSJason M. Bills } 11664851d45dSJason M. Bills } 116715a86ff6SJason M. Bills } 11684851d45dSJason M. Bills 116995820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 117095820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 117195820184SJason M. Bills // between the '.' and the '+', so just remove them. 1172f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1173f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 117495820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1175c4bf6374SJason M. Bills { 117695820184SJason M. Bills timestamp.erase(dot, plus - dot); 1177c4bf6374SJason M. Bills } 1178c4bf6374SJason M. Bills 1179c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 11809c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 118184afc48bSJason M. Bills logEntryJson["@odata.id"] = 118284afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID; 118384afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 118484afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 118584afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 118684afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 118784afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 118884afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 118984afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 119084afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1191ac992cdeSJason M. Bills return LogParseError::success; 1192c4bf6374SJason M. Bills } 1193c4bf6374SJason M. Bills 11947e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1195c4bf6374SJason M. Bills { 119622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 11978b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1198002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1199002d39b4SEd Tanous [&app](const crow::Request& req, 120022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 120122d268cbSEd Tanous const std::string& systemName) { 1202c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1203c937d2bfSEd Tanous .canDelegateTop = true, 1204c937d2bfSEd Tanous .canDelegateSkip = true, 1205c937d2bfSEd Tanous }; 1206c937d2bfSEd Tanous query_param::Query delegatedQuery; 1207c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 12083ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1209c4bf6374SJason M. Bills { 1210c4bf6374SJason M. Bills return; 1211c4bf6374SJason M. Bills } 121222d268cbSEd Tanous if (systemName != "system") 121322d268cbSEd Tanous { 121422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 121522d268cbSEd Tanous systemName); 121622d268cbSEd Tanous return; 121722d268cbSEd Tanous } 121822d268cbSEd Tanous 12195143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 12203648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 12213648c8beSEd Tanous 12227e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 12237e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1224c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1225c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1226c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1227029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1228c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1229c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1230c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1231cb92c03bSAndrew Geissler 12324978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1233c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 12347e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 12357e860f15SJohn Edward Broadbent // entry 123695820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 123795820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1238b01bf299SEd Tanous uint64_t entryCount = 0; 1239cd225da8SJason M. Bills std::string logEntry; 124095820184SJason M. Bills 12417e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 12427e860f15SJohn Edward Broadbent // backwards 1243002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1244002d39b4SEd Tanous it++) 1245c4bf6374SJason M. Bills { 1246cd225da8SJason M. Bills std::ifstream logStream(*it); 124795820184SJason M. Bills if (!logStream.is_open()) 1248c4bf6374SJason M. Bills { 1249c4bf6374SJason M. Bills continue; 1250c4bf6374SJason M. Bills } 1251c4bf6374SJason M. Bills 1252e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1253e85d6b16SJason M. Bills bool firstEntry = true; 125495820184SJason M. Bills while (std::getline(logStream, logEntry)) 125595820184SJason M. Bills { 1256c4bf6374SJason M. Bills std::string idStr; 1257e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1258c4bf6374SJason M. Bills { 1259c4bf6374SJason M. Bills continue; 1260c4bf6374SJason M. Bills } 1261e85d6b16SJason M. Bills firstEntry = false; 1262e85d6b16SJason M. Bills 1263de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1264ac992cdeSJason M. Bills LogParseError status = 1265ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1266ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1267ac992cdeSJason M. Bills { 1268ac992cdeSJason M. Bills continue; 1269ac992cdeSJason M. Bills } 1270ac992cdeSJason M. Bills if (status != LogParseError::success) 1271c4bf6374SJason M. Bills { 1272c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1273c4bf6374SJason M. Bills return; 1274c4bf6374SJason M. Bills } 1275de703c5dSJason M. Bills 1276de703c5dSJason M. Bills entryCount++; 1277de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1278de703c5dSJason M. Bills // start) and top (number of entries to display) 12793648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1280de703c5dSJason M. Bills { 1281de703c5dSJason M. Bills continue; 1282de703c5dSJason M. Bills } 1283de703c5dSJason M. Bills 1284de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1285c4bf6374SJason M. Bills } 128695820184SJason M. Bills } 1287c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 12883648c8beSEd Tanous if (skip + top < entryCount) 1289c4bf6374SJason M. Bills { 1290c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 12914978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 12923648c8beSEd Tanous std::to_string(skip + top); 1293c4bf6374SJason M. Bills } 12947e860f15SJohn Edward Broadbent }); 1295897967deSJason M. Bills } 1296897967deSJason M. Bills 12977e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1298897967deSJason M. Bills { 12997e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 130022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1301ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 13027e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 130345ca1b86SEd Tanous [&app](const crow::Request& req, 13047e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 130522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 13063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 130745ca1b86SEd Tanous { 130845ca1b86SEd Tanous return; 130945ca1b86SEd Tanous } 131022d268cbSEd Tanous 131122d268cbSEd Tanous if (systemName != "system") 131222d268cbSEd Tanous { 131322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 131422d268cbSEd Tanous systemName); 131522d268cbSEd Tanous return; 131622d268cbSEd Tanous } 131722d268cbSEd Tanous 13187e860f15SJohn Edward Broadbent const std::string& targetID = param; 13198d1b46d7Szhanghch05 13207e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 13217e860f15SJohn Edward Broadbent // entry to find the target entry 1322897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1323897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1324897967deSJason M. Bills std::string logEntry; 1325897967deSJason M. Bills 13267e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13277e860f15SJohn Edward Broadbent // backwards 1328002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1329002d39b4SEd Tanous it++) 1330897967deSJason M. Bills { 1331897967deSJason M. Bills std::ifstream logStream(*it); 1332897967deSJason M. Bills if (!logStream.is_open()) 1333897967deSJason M. Bills { 1334897967deSJason M. Bills continue; 1335897967deSJason M. Bills } 1336897967deSJason M. Bills 1337897967deSJason M. Bills // Reset the unique ID on the first entry 1338897967deSJason M. Bills bool firstEntry = true; 1339897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1340897967deSJason M. Bills { 1341897967deSJason M. Bills std::string idStr; 1342897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1343897967deSJason M. Bills { 1344897967deSJason M. Bills continue; 1345897967deSJason M. Bills } 1346897967deSJason M. Bills firstEntry = false; 1347897967deSJason M. Bills 1348897967deSJason M. Bills if (idStr == targetID) 1349897967deSJason M. Bills { 1350de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1351ac992cdeSJason M. Bills LogParseError status = 1352ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1353ac992cdeSJason M. Bills if (status != LogParseError::success) 1354897967deSJason M. Bills { 1355897967deSJason M. Bills messages::internalError(asyncResp->res); 1356897967deSJason M. Bills return; 1357897967deSJason M. Bills } 1358d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1359897967deSJason M. Bills return; 1360897967deSJason M. Bills } 1361897967deSJason M. Bills } 1362897967deSJason M. Bills } 1363897967deSJason M. Bills // Requested ID was not found 1364*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 13657e860f15SJohn Edward Broadbent }); 136608a4e4b5SAnthony Wilson } 136708a4e4b5SAnthony Wilson 13687e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 136908a4e4b5SAnthony Wilson { 137022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1371ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1372002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1373002d39b4SEd Tanous [&app](const crow::Request& req, 137422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 137522d268cbSEd Tanous const std::string& systemName) { 13763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 137745ca1b86SEd Tanous { 137845ca1b86SEd Tanous return; 137945ca1b86SEd Tanous } 138022d268cbSEd Tanous if (systemName != "system") 138122d268cbSEd Tanous { 138222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 138322d268cbSEd Tanous systemName); 138422d268cbSEd Tanous return; 138522d268cbSEd Tanous } 138622d268cbSEd Tanous 13877e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13887e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 138908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 139008a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 139108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 139208a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 139308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 139408a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 139508a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 139608a4e4b5SAnthony Wilson 1397cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1398cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1399cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 1400cb92c03bSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1401914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1402cb92c03bSAndrew Geissler if (ec) 1403cb92c03bSAndrew Geissler { 1404cb92c03bSAndrew Geissler // TODO Handle for specific error code 1405cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1406002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1407cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1408cb92c03bSAndrew Geissler return; 1409cb92c03bSAndrew Geissler } 1410002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1411cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 14129eb808c1SEd Tanous for (const auto& objectPath : resp) 1413cb92c03bSAndrew Geissler { 1414914e2d5dSEd Tanous const uint32_t* id = nullptr; 1415c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1416c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1417914e2d5dSEd Tanous const std::string* severity = nullptr; 1418914e2d5dSEd Tanous const std::string* message = nullptr; 1419914e2d5dSEd Tanous const std::string* filePath = nullptr; 14209c11a172SVijay Lobo const std::string* resolution = nullptr; 142175710de2SXiaochao Ma bool resolved = false; 14229eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1423f86bb901SAdriana Kobylak { 1424f86bb901SAdriana Kobylak if (interfaceMap.first == 1425f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1426f86bb901SAdriana Kobylak { 1427002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1428cb92c03bSAndrew Geissler { 1429cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1430cb92c03bSAndrew Geissler { 1431002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1432cb92c03bSAndrew Geissler } 1433cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1434cb92c03bSAndrew Geissler { 1435002d39b4SEd Tanous timestamp = 1436002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 14377e860f15SJohn Edward Broadbent } 1438002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 14397e860f15SJohn Edward Broadbent { 1440002d39b4SEd Tanous updateTimestamp = 1441002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 14427e860f15SJohn Edward Broadbent } 14437e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 14447e860f15SJohn Edward Broadbent { 14457e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 14467e860f15SJohn Edward Broadbent &propertyMap.second); 14477e860f15SJohn Edward Broadbent } 14489c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 14499c11a172SVijay Lobo { 14509c11a172SVijay Lobo resolution = std::get_if<std::string>( 14519c11a172SVijay Lobo &propertyMap.second); 14529c11a172SVijay Lobo } 14537e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 14547e860f15SJohn Edward Broadbent { 14557e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 14567e860f15SJohn Edward Broadbent &propertyMap.second); 14577e860f15SJohn Edward Broadbent } 14587e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 14597e860f15SJohn Edward Broadbent { 1460914e2d5dSEd Tanous const bool* resolveptr = 1461002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 14627e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 14637e860f15SJohn Edward Broadbent { 1464002d39b4SEd Tanous messages::internalError(asyncResp->res); 14657e860f15SJohn Edward Broadbent return; 14667e860f15SJohn Edward Broadbent } 14677e860f15SJohn Edward Broadbent resolved = *resolveptr; 14687e860f15SJohn Edward Broadbent } 14697e860f15SJohn Edward Broadbent } 14707e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 14717e860f15SJohn Edward Broadbent severity == nullptr) 14727e860f15SJohn Edward Broadbent { 14737e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 14747e860f15SJohn Edward Broadbent return; 14757e860f15SJohn Edward Broadbent } 14767e860f15SJohn Edward Broadbent } 14777e860f15SJohn Edward Broadbent else if (interfaceMap.first == 14787e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 14797e860f15SJohn Edward Broadbent { 1480002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 14817e860f15SJohn Edward Broadbent { 14827e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 14837e860f15SJohn Edward Broadbent { 14847e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 14857e860f15SJohn Edward Broadbent &propertyMap.second); 14867e860f15SJohn Edward Broadbent } 14877e860f15SJohn Edward Broadbent } 14887e860f15SJohn Edward Broadbent } 14897e860f15SJohn Edward Broadbent } 14907e860f15SJohn Edward Broadbent // Object path without the 14917e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 14927e860f15SJohn Edward Broadbent // and continue. 14937e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1494c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1495c419c759SEd Tanous updateTimestamp == nullptr) 14967e860f15SJohn Edward Broadbent { 14977e860f15SJohn Edward Broadbent continue; 14987e860f15SJohn Edward Broadbent } 14997e860f15SJohn Edward Broadbent entriesArray.push_back({}); 15007e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 15019c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 15027e860f15SJohn Edward Broadbent thisEntry["@odata.id"] = 15030fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 15047e860f15SJohn Edward Broadbent std::to_string(*id); 15057e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 15067e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 15077e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 15087e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 15099c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 15109c11a172SVijay Lobo { 15119c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 15129c11a172SVijay Lobo } 15137e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 15147e860f15SJohn Edward Broadbent thisEntry["Severity"] = 15157e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 15167e860f15SJohn Edward Broadbent thisEntry["Created"] = 15172b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 15187e860f15SJohn Edward Broadbent thisEntry["Modified"] = 15192b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 15207e860f15SJohn Edward Broadbent if (filePath != nullptr) 15217e860f15SJohn Edward Broadbent { 15227e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 15230fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 15247e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 15257e860f15SJohn Edward Broadbent } 15267e860f15SJohn Edward Broadbent } 1527002d39b4SEd Tanous std::sort( 1528002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1529002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 15307e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 15317e860f15SJohn Edward Broadbent }); 15327e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 15337e860f15SJohn Edward Broadbent entriesArray.size(); 15347e860f15SJohn Edward Broadbent }, 15357e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 15367e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 15377e860f15SJohn Edward Broadbent }); 15387e860f15SJohn Edward Broadbent } 15397e860f15SJohn Edward Broadbent 15407e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 15417e860f15SJohn Edward Broadbent { 15427e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 154322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1544ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1545002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1546002d39b4SEd Tanous [&app](const crow::Request& req, 15477e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 154822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 15493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 15507e860f15SJohn Edward Broadbent { 155145ca1b86SEd Tanous return; 155245ca1b86SEd Tanous } 155322d268cbSEd Tanous if (systemName != "system") 155422d268cbSEd Tanous { 155522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 155622d268cbSEd Tanous systemName); 155722d268cbSEd Tanous return; 155822d268cbSEd Tanous } 155922d268cbSEd Tanous 15607e860f15SJohn Edward Broadbent std::string entryID = param; 15617e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 15627e860f15SJohn Edward Broadbent 15637e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 15647e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1565d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1566d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1567d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 1568002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1569b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 15707e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 15717e860f15SJohn Edward Broadbent { 1572d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1573d1bde9e5SKrzysztof Grobelny entryID); 15747e860f15SJohn Edward Broadbent return; 15757e860f15SJohn Edward Broadbent } 15767e860f15SJohn Edward Broadbent if (ec) 15777e860f15SJohn Edward Broadbent { 15780fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1579002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 15807e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 15817e860f15SJohn Edward Broadbent return; 15827e860f15SJohn Edward Broadbent } 1583914e2d5dSEd Tanous const uint32_t* id = nullptr; 1584c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1585c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1586914e2d5dSEd Tanous const std::string* severity = nullptr; 1587914e2d5dSEd Tanous const std::string* message = nullptr; 1588914e2d5dSEd Tanous const std::string* filePath = nullptr; 15899c11a172SVijay Lobo const std::string* resolution = nullptr; 15907e860f15SJohn Edward Broadbent bool resolved = false; 15917e860f15SJohn Edward Broadbent 1592d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1593d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1594d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 15959c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 15969c11a172SVijay Lobo "Resolution", resolution, "Path", filePath); 1597d1bde9e5SKrzysztof Grobelny 1598d1bde9e5SKrzysztof Grobelny if (!success) 159975710de2SXiaochao Ma { 160075710de2SXiaochao Ma messages::internalError(asyncResp->res); 160175710de2SXiaochao Ma return; 160275710de2SXiaochao Ma } 1603d1bde9e5SKrzysztof Grobelny 1604002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 1605002d39b4SEd Tanous timestamp == nullptr || updateTimestamp == nullptr) 1606f86bb901SAdriana Kobylak { 1607ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1608271584abSEd Tanous return; 1609271584abSEd Tanous } 1610f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 16119c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1612f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 16130fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1614f86bb901SAdriana Kobylak std::to_string(*id); 161545ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1616f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1617f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1618f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 16199c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16209c11a172SVijay Lobo { 16219c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 16229c11a172SVijay Lobo } 1623f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1624f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1625f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1626f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 16272b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1628f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 16292b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1630f86bb901SAdriana Kobylak if (filePath != nullptr) 1631f86bb901SAdriana Kobylak { 1632f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1633e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1634e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1635f86bb901SAdriana Kobylak } 1636d1bde9e5SKrzysztof Grobelny }); 16377e860f15SJohn Edward Broadbent }); 1638336e96c6SChicago Duan 16397e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 164022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1641ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 16427e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 164345ca1b86SEd Tanous [&app](const crow::Request& req, 16447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 164522d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 16463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 164745ca1b86SEd Tanous { 164845ca1b86SEd Tanous return; 164945ca1b86SEd Tanous } 165022d268cbSEd Tanous if (systemName != "system") 165122d268cbSEd Tanous { 165222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 165322d268cbSEd Tanous systemName); 165422d268cbSEd Tanous return; 165522d268cbSEd Tanous } 165675710de2SXiaochao Ma std::optional<bool> resolved; 165775710de2SXiaochao Ma 165815ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 16597e860f15SJohn Edward Broadbent resolved)) 166075710de2SXiaochao Ma { 166175710de2SXiaochao Ma return; 166275710de2SXiaochao Ma } 166375710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 166475710de2SXiaochao Ma 166575710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 16664f48d5f6SEd Tanous [asyncResp, entryId](const boost::system::error_code ec) { 166775710de2SXiaochao Ma if (ec) 166875710de2SXiaochao Ma { 166975710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 167075710de2SXiaochao Ma messages::internalError(asyncResp->res); 167175710de2SXiaochao Ma return; 167275710de2SXiaochao Ma } 167375710de2SXiaochao Ma }, 167475710de2SXiaochao Ma "xyz.openbmc_project.Logging", 167575710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 167675710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 167775710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1678168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 16797e860f15SJohn Edward Broadbent }); 168075710de2SXiaochao Ma 16817e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 168222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1683ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1684ed398213SEd Tanous 1685002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1686002d39b4SEd Tanous [&app](const crow::Request& req, 1687002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 168822d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16893ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1690336e96c6SChicago Duan { 169145ca1b86SEd Tanous return; 169245ca1b86SEd Tanous } 169322d268cbSEd Tanous if (systemName != "system") 169422d268cbSEd Tanous { 169522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 169622d268cbSEd Tanous systemName); 169722d268cbSEd Tanous return; 169822d268cbSEd Tanous } 1699336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1700336e96c6SChicago Duan 17017e860f15SJohn Edward Broadbent std::string entryID = param; 1702336e96c6SChicago Duan 1703336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1704336e96c6SChicago Duan 1705336e96c6SChicago Duan // Process response from Logging service. 1706002d39b4SEd Tanous auto respHandler = 1707002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 1708002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1709336e96c6SChicago Duan if (ec) 1710336e96c6SChicago Duan { 17113de8d8baSGeorge Liu if (ec.value() == EBADR) 17123de8d8baSGeorge Liu { 171345ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 171445ca1b86SEd Tanous entryID); 17153de8d8baSGeorge Liu return; 17163de8d8baSGeorge Liu } 1717336e96c6SChicago Duan // TODO Handle for specific error code 17180fda0f12SGeorge Liu BMCWEB_LOG_ERROR 17190fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1720336e96c6SChicago Duan << ec; 1721336e96c6SChicago Duan asyncResp->res.result( 1722336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1723336e96c6SChicago Duan return; 1724336e96c6SChicago Duan } 1725336e96c6SChicago Duan 1726336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1727336e96c6SChicago Duan }; 1728336e96c6SChicago Duan 1729336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1730336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1731336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1732336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1733336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 17347e860f15SJohn Edward Broadbent }); 1735400fd1fbSAdriana Kobylak } 1736400fd1fbSAdriana Kobylak 17377e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1738400fd1fbSAdriana Kobylak { 17390fda0f12SGeorge Liu BMCWEB_ROUTE( 17400fda0f12SGeorge Liu app, 174122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1742ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 17437e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 174445ca1b86SEd Tanous [&app](const crow::Request& req, 17457e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17487e860f15SJohn Edward Broadbent { 174945ca1b86SEd Tanous return; 175045ca1b86SEd Tanous } 175199351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 175299351cd8SEd Tanous req.getHeaderValue("Accept"), 17534a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1754400fd1fbSAdriana Kobylak { 1755002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1756400fd1fbSAdriana Kobylak return; 1757400fd1fbSAdriana Kobylak } 175822d268cbSEd Tanous if (systemName != "system") 175922d268cbSEd Tanous { 176022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 176122d268cbSEd Tanous systemName); 176222d268cbSEd Tanous return; 176322d268cbSEd Tanous } 1764400fd1fbSAdriana Kobylak 17657e860f15SJohn Edward Broadbent std::string entryID = param; 1766400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1767400fd1fbSAdriana Kobylak 1768400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 1769002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1770400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1771400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1772400fd1fbSAdriana Kobylak { 1773002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1774002d39b4SEd Tanous entryID); 1775400fd1fbSAdriana Kobylak return; 1776400fd1fbSAdriana Kobylak } 1777400fd1fbSAdriana Kobylak if (ec) 1778400fd1fbSAdriana Kobylak { 1779400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1780400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1781400fd1fbSAdriana Kobylak return; 1782400fd1fbSAdriana Kobylak } 1783400fd1fbSAdriana Kobylak 1784400fd1fbSAdriana Kobylak int fd = -1; 1785400fd1fbSAdriana Kobylak fd = dup(unixfd); 1786400fd1fbSAdriana Kobylak if (fd == -1) 1787400fd1fbSAdriana Kobylak { 1788400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1789400fd1fbSAdriana Kobylak return; 1790400fd1fbSAdriana Kobylak } 1791400fd1fbSAdriana Kobylak 1792400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1793400fd1fbSAdriana Kobylak if (size == -1) 1794400fd1fbSAdriana Kobylak { 1795400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1796400fd1fbSAdriana Kobylak return; 1797400fd1fbSAdriana Kobylak } 1798400fd1fbSAdriana Kobylak 1799400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1800400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1801400fd1fbSAdriana Kobylak if (size > maxFileSize) 1802400fd1fbSAdriana Kobylak { 1803002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1804400fd1fbSAdriana Kobylak << maxFileSize; 1805400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1806400fd1fbSAdriana Kobylak return; 1807400fd1fbSAdriana Kobylak } 1808400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1809400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1810400fd1fbSAdriana Kobylak if (rc == -1) 1811400fd1fbSAdriana Kobylak { 1812400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1813400fd1fbSAdriana Kobylak return; 1814400fd1fbSAdriana Kobylak } 1815400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1816400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1817400fd1fbSAdriana Kobylak { 1818400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1819400fd1fbSAdriana Kobylak return; 1820400fd1fbSAdriana Kobylak } 1821400fd1fbSAdriana Kobylak close(fd); 1822400fd1fbSAdriana Kobylak 1823400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 1824002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 1825400fd1fbSAdriana Kobylak 1826d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 1827400fd1fbSAdriana Kobylak "application/octet-stream"); 1828d9f6c621SEd Tanous asyncResp->res.addHeader( 1829d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 1830400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 1831400fd1fbSAdriana Kobylak }, 1832400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 1833400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 1834400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 18357e860f15SJohn Edward Broadbent }); 18361da66f75SEd Tanous } 18371da66f75SEd Tanous 1838b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 1839b7028ebfSSpencer Ku 1840b7028ebfSSpencer Ku inline bool 1841b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 1842b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 1843b7028ebfSSpencer Ku { 1844b7028ebfSSpencer Ku std::error_code ec; 1845b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 1846b7028ebfSSpencer Ku if (ec) 1847b7028ebfSSpencer Ku { 1848b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 1849b7028ebfSSpencer Ku return false; 1850b7028ebfSSpencer Ku } 1851b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 1852b7028ebfSSpencer Ku { 1853b7028ebfSSpencer Ku std::string filename = it.path().filename(); 1854b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 1855b7028ebfSSpencer Ku // path 185611ba3979SEd Tanous if (filename.starts_with("log")) 1857b7028ebfSSpencer Ku { 1858b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 1859b7028ebfSSpencer Ku } 1860b7028ebfSSpencer Ku } 1861b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 1862b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 1863b7028ebfSSpencer Ku // descending order. 1864b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 1865b7028ebfSSpencer Ku AlphanumLess<std::string>()); 1866b7028ebfSSpencer Ku 1867b7028ebfSSpencer Ku return true; 1868b7028ebfSSpencer Ku } 1869b7028ebfSSpencer Ku 187002cad96eSEd Tanous inline bool getHostLoggerEntries( 187102cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 187202cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 1873b7028ebfSSpencer Ku { 1874b7028ebfSSpencer Ku GzFileReader logFile; 1875b7028ebfSSpencer Ku 1876b7028ebfSSpencer Ku // Go though all log files and expose host logs. 1877b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 1878b7028ebfSSpencer Ku { 1879b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 1880b7028ebfSSpencer Ku { 1881b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 1882b7028ebfSSpencer Ku return false; 1883b7028ebfSSpencer Ku } 1884b7028ebfSSpencer Ku } 1885b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 1886b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 1887b7028ebfSSpencer Ku if (!lastMessage.empty()) 1888b7028ebfSSpencer Ku { 1889b7028ebfSSpencer Ku logCount++; 1890b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 1891b7028ebfSSpencer Ku { 1892b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 1893b7028ebfSSpencer Ku } 1894b7028ebfSSpencer Ku } 1895b7028ebfSSpencer Ku return true; 1896b7028ebfSSpencer Ku } 1897b7028ebfSSpencer Ku 1898b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 1899b7028ebfSSpencer Ku const std::string& msg, 19006d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 1901b7028ebfSSpencer Ku { 1902b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 19039c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 19046d6574c9SJason M. Bills logEntryJson["@odata.id"] = 1905b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" + 19066d6574c9SJason M. Bills logEntryID; 19076d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 19086d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 19096d6574c9SJason M. Bills logEntryJson["Message"] = msg; 19106d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 19116d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 19126d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 1913b7028ebfSSpencer Ku } 1914b7028ebfSSpencer Ku 1915b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 1916b7028ebfSSpencer Ku { 191722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 1918b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 19191476687dSEd Tanous .methods(boost::beast::http::verb::get)( 19201476687dSEd Tanous [&app](const crow::Request& req, 192122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 192222d268cbSEd Tanous const std::string& systemName) { 19233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 192445ca1b86SEd Tanous { 192545ca1b86SEd Tanous return; 192645ca1b86SEd Tanous } 192722d268cbSEd Tanous if (systemName != "system") 192822d268cbSEd Tanous { 192922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 193022d268cbSEd Tanous systemName); 193122d268cbSEd Tanous return; 193222d268cbSEd Tanous } 1933b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 1934b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 1935b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 1936b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 1937b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 1938b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 1939b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 19401476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 19411476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 1942b7028ebfSSpencer Ku }); 1943b7028ebfSSpencer Ku } 1944b7028ebfSSpencer Ku 1945b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 1946b7028ebfSSpencer Ku { 1947b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 194822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 1949b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 1950002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1951002d39b4SEd Tanous [&app](const crow::Request& req, 195222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 195322d268cbSEd Tanous const std::string& systemName) { 1954c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1955c937d2bfSEd Tanous .canDelegateTop = true, 1956c937d2bfSEd Tanous .canDelegateSkip = true, 1957c937d2bfSEd Tanous }; 1958c937d2bfSEd Tanous query_param::Query delegatedQuery; 1959c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 19603ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1961b7028ebfSSpencer Ku { 1962b7028ebfSSpencer Ku return; 1963b7028ebfSSpencer Ku } 196422d268cbSEd Tanous if (systemName != "system") 196522d268cbSEd Tanous { 196622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 196722d268cbSEd Tanous systemName); 196822d268cbSEd Tanous return; 196922d268cbSEd Tanous } 1970b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 1971b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 1972b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 1973b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 1974b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 1975b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 1976b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 19770fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1978b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 1979b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 1980b7028ebfSSpencer Ku 1981b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 1982b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 1983b7028ebfSSpencer Ku { 1984b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 1985b7028ebfSSpencer Ku return; 1986b7028ebfSSpencer Ku } 19873648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 19883648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 19895143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 1990b7028ebfSSpencer Ku size_t logCount = 0; 1991b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 1992b7028ebfSSpencer Ku // control by skip and top. 1993b7028ebfSSpencer Ku std::vector<std::string> logEntries; 19943648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 19953648c8beSEd Tanous logCount)) 1996b7028ebfSSpencer Ku { 1997b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 1998b7028ebfSSpencer Ku return; 1999b7028ebfSSpencer Ku } 2000b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2001b7028ebfSSpencer Ku // log count 200226f6976fSEd Tanous if (logEntries.empty()) 2003b7028ebfSSpencer Ku { 2004b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2005b7028ebfSSpencer Ku return; 2006b7028ebfSSpencer Ku } 200726f6976fSEd Tanous if (!logEntries.empty()) 2008b7028ebfSSpencer Ku { 2009b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2010b7028ebfSSpencer Ku { 20116d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 20123648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 20133648c8beSEd Tanous hostLogEntry); 20146d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2015b7028ebfSSpencer Ku } 2016b7028ebfSSpencer Ku 2017b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 20183648c8beSEd Tanous if (skip + top < logCount) 2019b7028ebfSSpencer Ku { 2020b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 20210fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 20223648c8beSEd Tanous std::to_string(skip + top); 2023b7028ebfSSpencer Ku } 2024b7028ebfSSpencer Ku } 2025b7028ebfSSpencer Ku }); 2026b7028ebfSSpencer Ku } 2027b7028ebfSSpencer Ku 2028b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2029b7028ebfSSpencer Ku { 2030b7028ebfSSpencer Ku BMCWEB_ROUTE( 203122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2032b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2033b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 203445ca1b86SEd Tanous [&app](const crow::Request& req, 2035b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 203622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 20373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 203845ca1b86SEd Tanous { 203945ca1b86SEd Tanous return; 204045ca1b86SEd Tanous } 204122d268cbSEd Tanous if (systemName != "system") 204222d268cbSEd Tanous { 204322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 204422d268cbSEd Tanous systemName); 204522d268cbSEd Tanous return; 204622d268cbSEd Tanous } 2047b7028ebfSSpencer Ku const std::string& targetID = param; 2048b7028ebfSSpencer Ku 2049b7028ebfSSpencer Ku uint64_t idInt = 0; 2050ca45aa3cSEd Tanous 2051ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2052ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2053ca45aa3cSEd Tanous 2054ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 2055*9db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 2056*9db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2057b7028ebfSSpencer Ku { 2058*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2059b7028ebfSSpencer Ku return; 2060b7028ebfSSpencer Ku } 2061b7028ebfSSpencer Ku 2062b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2063b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2064b7028ebfSSpencer Ku { 2065b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2066b7028ebfSSpencer Ku return; 2067b7028ebfSSpencer Ku } 2068b7028ebfSSpencer Ku 2069b7028ebfSSpencer Ku size_t logCount = 0; 20703648c8beSEd Tanous size_t top = 1; 2071b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2072b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2073b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2074b7028ebfSSpencer Ku // get that entry 2075002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2076002d39b4SEd Tanous logCount)) 2077b7028ebfSSpencer Ku { 2078b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2079b7028ebfSSpencer Ku return; 2080b7028ebfSSpencer Ku } 2081b7028ebfSSpencer Ku 2082b7028ebfSSpencer Ku if (!logEntries.empty()) 2083b7028ebfSSpencer Ku { 20846d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 20856d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 20866d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2087b7028ebfSSpencer Ku return; 2088b7028ebfSSpencer Ku } 2089b7028ebfSSpencer Ku 2090b7028ebfSSpencer Ku // Requested ID was not found 2091*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2092b7028ebfSSpencer Ku }); 2093b7028ebfSSpencer Ku } 2094b7028ebfSSpencer Ku 2095fdd26906SClaire Weinan constexpr char const* dumpManagerIface = 2096fdd26906SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll"; 2097dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2098fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2099fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 21001da66f75SEd Tanous { 21013ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 210245ca1b86SEd Tanous { 210345ca1b86SEd Tanous return; 210445ca1b86SEd Tanous } 21057e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 21067e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2107e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 21081da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2109e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2110e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2111002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2112e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 21131da66f75SEd Tanous "Collection of LogServices for this Manager"; 2114002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2115c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2116fdd26906SClaire Weinan 2117c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2118613dabeaSEd Tanous nlohmann::json::object_t journal; 2119613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2120613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2121c4bf6374SJason M. Bills #endif 2122fdd26906SClaire Weinan 2123fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2124fdd26906SClaire Weinan 2125fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 2126fdd26906SClaire Weinan auto respHandler = 2127fdd26906SClaire Weinan [asyncResp]( 2128fdd26906SClaire Weinan const boost::system::error_code ec, 2129fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2130fdd26906SClaire Weinan if (ec) 2131fdd26906SClaire Weinan { 2132fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2133dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2134fdd26906SClaire Weinan << ec; 2135fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2136fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2137fdd26906SClaire Weinan return; 2138fdd26906SClaire Weinan } 2139fdd26906SClaire Weinan 2140fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2141fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2142fdd26906SClaire Weinan 2143fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2144fdd26906SClaire Weinan { 2145fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2146fdd26906SClaire Weinan { 2147613dabeaSEd Tanous nlohmann::json::object_t member; 2148613dabeaSEd Tanous member["@odata.id"] = 2149613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2150613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2151fdd26906SClaire Weinan } 2152fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2153fdd26906SClaire Weinan { 2154613dabeaSEd Tanous nlohmann::json::object_t member; 2155613dabeaSEd Tanous member["@odata.id"] = 2156613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2157613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2158fdd26906SClaire Weinan } 2159fdd26906SClaire Weinan } 2160fdd26906SClaire Weinan 2161e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2162fdd26906SClaire Weinan logServiceArrayLocal.size(); 2163fdd26906SClaire Weinan }; 2164fdd26906SClaire Weinan 2165fdd26906SClaire Weinan crow::connections::systemBus->async_method_call( 2166fdd26906SClaire Weinan respHandler, "xyz.openbmc_project.ObjectMapper", 2167fdd26906SClaire Weinan "/xyz/openbmc_project/object_mapper", 2168fdd26906SClaire Weinan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 2169fdd26906SClaire Weinan "/xyz/openbmc_project/dump", 0, 2170fdd26906SClaire Weinan std::array<const char*, 1>{dumpManagerIface}); 2171fdd26906SClaire Weinan #endif 2172fdd26906SClaire Weinan } 2173fdd26906SClaire Weinan 2174fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2175fdd26906SClaire Weinan { 2176fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2177fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2178fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2179dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2180e1f26343SJason M. Bills } 2181e1f26343SJason M. Bills 21827e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2183e1f26343SJason M. Bills { 21847e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2185ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 21867e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 218745ca1b86SEd Tanous [&app](const crow::Request& req, 218845ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 21893ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 21907e860f15SJohn Edward Broadbent { 219145ca1b86SEd Tanous return; 219245ca1b86SEd Tanous } 2193e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2194e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 21950f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 21960f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2197002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2198002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2199c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "BMC Journal"; 2200e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 22017c8c4058STejas Patil 22027c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 22032b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2204002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 22057c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 22067c8c4058STejas Patil redfishDateTimeOffset.second; 22077c8c4058STejas Patil 22081476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 22091476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 22107e860f15SJohn Edward Broadbent }); 2211e1f26343SJason M. Bills } 2212e1f26343SJason M. Bills 22133a48b3a2SJason M. Bills static int 22143a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2215e1f26343SJason M. Bills sd_journal* journal, 22163a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2217e1f26343SJason M. Bills { 2218e1f26343SJason M. Bills // Get the Log Entry contents 2219e1f26343SJason M. Bills int ret = 0; 2220e1f26343SJason M. Bills 2221a8fe54f0SJason M. Bills std::string message; 2222a8fe54f0SJason M. Bills std::string_view syslogID; 2223a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2224a8fe54f0SJason M. Bills if (ret < 0) 2225a8fe54f0SJason M. Bills { 2226a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2227a8fe54f0SJason M. Bills << strerror(-ret); 2228a8fe54f0SJason M. Bills } 2229a8fe54f0SJason M. Bills if (!syslogID.empty()) 2230a8fe54f0SJason M. Bills { 2231a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2232a8fe54f0SJason M. Bills } 2233a8fe54f0SJason M. Bills 223439e77504SEd Tanous std::string_view msg; 223516428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2236e1f26343SJason M. Bills if (ret < 0) 2237e1f26343SJason M. Bills { 2238e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2239e1f26343SJason M. Bills return 1; 2240e1f26343SJason M. Bills } 2241a8fe54f0SJason M. Bills message += std::string(msg); 2242e1f26343SJason M. Bills 2243e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2244271584abSEd Tanous long int severity = 8; // Default to an invalid priority 224516428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2246e1f26343SJason M. Bills if (ret < 0) 2247e1f26343SJason M. Bills { 2248e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2249e1f26343SJason M. Bills } 2250e1f26343SJason M. Bills 2251e1f26343SJason M. Bills // Get the Created time from the timestamp 225216428a1aSJason M. Bills std::string entryTimeStr; 225316428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2254e1f26343SJason M. Bills { 225516428a1aSJason M. Bills return 1; 2256e1f26343SJason M. Bills } 2257e1f26343SJason M. Bills 2258e1f26343SJason M. Bills // Fill in the log entry with the gathered data 22599c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 226084afc48bSJason M. Bills bmcJournalLogEntryJson["@odata.id"] = 226184afc48bSJason M. Bills "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" + 226284afc48bSJason M. Bills bmcJournalLogEntryID; 226384afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 226484afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 226584afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 226684afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 226784afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2268738c1e61SPatrick Williams : severity <= 4 ? "Warning" 226984afc48bSJason M. Bills : "OK"; 227084afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 227184afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2272e1f26343SJason M. Bills return 0; 2273e1f26343SJason M. Bills } 2274e1f26343SJason M. Bills 22757e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2276e1f26343SJason M. Bills { 22777e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2278ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2279002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2280002d39b4SEd Tanous [&app](const crow::Request& req, 2281002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2282c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2283c937d2bfSEd Tanous .canDelegateTop = true, 2284c937d2bfSEd Tanous .canDelegateSkip = true, 2285c937d2bfSEd Tanous }; 2286c937d2bfSEd Tanous query_param::Query delegatedQuery; 2287c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22883ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2289193ad2faSJason M. Bills { 2290193ad2faSJason M. Bills return; 2291193ad2faSJason M. Bills } 22923648c8beSEd Tanous 22933648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 22945143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 22953648c8beSEd Tanous 22967e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22977e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2298e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2299e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 23000f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23010f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2302e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2303e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2304e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 23050fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2306e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2307e1f26343SJason M. Bills 23087e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 23097e860f15SJohn Edward Broadbent // unique ID for each entry 2310e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2311e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2312e1f26343SJason M. Bills if (ret < 0) 2313e1f26343SJason M. Bills { 2314002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2315f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2316e1f26343SJason M. Bills return; 2317e1f26343SJason M. Bills } 23180fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 23190fda0f12SGeorge Liu journalTmp, sd_journal_close); 2320e1f26343SJason M. Bills journalTmp = nullptr; 2321b01bf299SEd Tanous uint64_t entryCount = 0; 2322e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2323e85d6b16SJason M. Bills bool firstEntry = true; 2324e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2325e1f26343SJason M. Bills { 2326193ad2faSJason M. Bills entryCount++; 23277e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 23287e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 23293648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2330193ad2faSJason M. Bills { 2331193ad2faSJason M. Bills continue; 2332193ad2faSJason M. Bills } 2333193ad2faSJason M. Bills 233416428a1aSJason M. Bills std::string idStr; 2335e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2336e1f26343SJason M. Bills { 2337e1f26343SJason M. Bills continue; 2338e1f26343SJason M. Bills } 2339e85d6b16SJason M. Bills firstEntry = false; 2340e85d6b16SJason M. Bills 23413a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2342c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2343c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2344e1f26343SJason M. Bills { 2345f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2346e1f26343SJason M. Bills return; 2347e1f26343SJason M. Bills } 23483a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2349e1f26343SJason M. Bills } 2350193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 23513648c8beSEd Tanous if (skip + top < entryCount) 2352193ad2faSJason M. Bills { 2353193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 23540fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 23553648c8beSEd Tanous std::to_string(skip + top); 2356193ad2faSJason M. Bills } 23577e860f15SJohn Edward Broadbent }); 2358e1f26343SJason M. Bills } 2359e1f26343SJason M. Bills 23607e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2361e1f26343SJason M. Bills { 23627e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 23637e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2364ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 23657e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 236645ca1b86SEd Tanous [&app](const crow::Request& req, 23677e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23687e860f15SJohn Edward Broadbent const std::string& entryID) { 23693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 237045ca1b86SEd Tanous { 237145ca1b86SEd Tanous return; 237245ca1b86SEd Tanous } 2373e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2374e1f26343SJason M. Bills uint64_t ts = 0; 2375271584abSEd Tanous uint64_t index = 0; 23768d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2377e1f26343SJason M. Bills { 237816428a1aSJason M. Bills return; 2379e1f26343SJason M. Bills } 2380e1f26343SJason M. Bills 2381e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2382e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2383e1f26343SJason M. Bills if (ret < 0) 2384e1f26343SJason M. Bills { 2385002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2386f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2387e1f26343SJason M. Bills return; 2388e1f26343SJason M. Bills } 2389002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2390002d39b4SEd Tanous journalTmp, sd_journal_close); 2391e1f26343SJason M. Bills journalTmp = nullptr; 23927e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 23937e860f15SJohn Edward Broadbent // index tracking the unique ID 2394af07e3f5SJason M. Bills std::string idStr; 2395af07e3f5SJason M. Bills bool firstEntry = true; 2396e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 23972056b6d1SManojkiran Eda if (ret < 0) 23982056b6d1SManojkiran Eda { 23992056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 24002056b6d1SManojkiran Eda << strerror(-ret); 24012056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 24022056b6d1SManojkiran Eda return; 24032056b6d1SManojkiran Eda } 2404271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2405e1f26343SJason M. Bills { 2406e1f26343SJason M. Bills sd_journal_next(journal.get()); 2407af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2408af07e3f5SJason M. Bills { 2409af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2410af07e3f5SJason M. Bills return; 2411af07e3f5SJason M. Bills } 2412af07e3f5SJason M. Bills firstEntry = false; 2413af07e3f5SJason M. Bills } 2414c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2415af07e3f5SJason M. Bills if (idStr != entryID) 2416c4bf6374SJason M. Bills { 2417*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2418c4bf6374SJason M. Bills return; 2419c4bf6374SJason M. Bills } 2420c4bf6374SJason M. Bills 24213a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2422c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 24233a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2424e1f26343SJason M. Bills { 2425f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2426e1f26343SJason M. Bills return; 2427e1f26343SJason M. Bills } 2428d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 24297e860f15SJohn Edward Broadbent }); 2430c9bb6861Sraviteja-b } 2431c9bb6861Sraviteja-b 2432fdd26906SClaire Weinan inline void 2433fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2434fdd26906SClaire Weinan const std::string& dumpType) 2435c9bb6861Sraviteja-b { 2436fdd26906SClaire Weinan std::string dumpPath; 2437fdd26906SClaire Weinan std::string overWritePolicy; 2438fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2439fdd26906SClaire Weinan 2440fdd26906SClaire Weinan if (dumpType == "BMC") 244145ca1b86SEd Tanous { 2442fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2443fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2444fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2445fdd26906SClaire Weinan } 2446fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2447fdd26906SClaire Weinan { 2448fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2449fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2450fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2451fdd26906SClaire Weinan } 2452fdd26906SClaire Weinan else if (dumpType == "System") 2453fdd26906SClaire Weinan { 2454fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2455fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2456fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2457fdd26906SClaire Weinan } 2458fdd26906SClaire Weinan else 2459fdd26906SClaire Weinan { 2460fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2461fdd26906SClaire Weinan << dumpType; 2462fdd26906SClaire Weinan messages::internalError(asyncResp->res); 246345ca1b86SEd Tanous return; 246445ca1b86SEd Tanous } 2465fdd26906SClaire Weinan 2466fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2467fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2468c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2469fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2470fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2471fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 24727c8c4058STejas Patil 24737c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 24742b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 24750fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 24767c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 24777c8c4058STejas Patil redfishDateTimeOffset.second; 24787c8c4058STejas Patil 2479fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2480002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 2481fdd26906SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 2482fdd26906SClaire Weinan 2483fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2484fdd26906SClaire Weinan { 2485002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 24861476687dSEd Tanous ["target"] = 2487fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2488fdd26906SClaire Weinan } 2489c9bb6861Sraviteja-b } 2490c9bb6861Sraviteja-b 2491fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2492fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2493fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 24947e860f15SJohn Edward Broadbent { 24953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 249645ca1b86SEd Tanous { 249745ca1b86SEd Tanous return; 249845ca1b86SEd Tanous } 2499fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2500fdd26906SClaire Weinan } 2501c9bb6861Sraviteja-b 250222d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 250322d268cbSEd Tanous crow::App& app, const crow::Request& req, 250422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 250522d268cbSEd Tanous const std::string& chassisId) 250622d268cbSEd Tanous { 250722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 250822d268cbSEd Tanous { 250922d268cbSEd Tanous return; 251022d268cbSEd Tanous } 251122d268cbSEd Tanous if (chassisId != "system") 251222d268cbSEd Tanous { 251322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 251422d268cbSEd Tanous return; 251522d268cbSEd Tanous } 251622d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 251722d268cbSEd Tanous } 251822d268cbSEd Tanous 2519fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2520fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2521fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2522fdd26906SClaire Weinan { 2523fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2524fdd26906SClaire Weinan { 2525fdd26906SClaire Weinan return; 2526fdd26906SClaire Weinan } 2527fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2528fdd26906SClaire Weinan } 2529fdd26906SClaire Weinan 253022d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 253122d268cbSEd Tanous crow::App& app, const crow::Request& req, 253222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 253322d268cbSEd Tanous const std::string& chassisId) 253422d268cbSEd Tanous { 253522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 253622d268cbSEd Tanous { 253722d268cbSEd Tanous return; 253822d268cbSEd Tanous } 253922d268cbSEd Tanous if (chassisId != "system") 254022d268cbSEd Tanous { 254122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 254222d268cbSEd Tanous return; 254322d268cbSEd Tanous } 254422d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 254522d268cbSEd Tanous } 254622d268cbSEd Tanous 2547fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2548fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2549fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2550fdd26906SClaire Weinan const std::string& dumpId) 2551fdd26906SClaire Weinan { 2552fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2553fdd26906SClaire Weinan { 2554fdd26906SClaire Weinan return; 2555fdd26906SClaire Weinan } 2556fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2557fdd26906SClaire Weinan } 255822d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 255922d268cbSEd Tanous crow::App& app, const crow::Request& req, 256022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 256122d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 256222d268cbSEd Tanous { 256322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 256422d268cbSEd Tanous { 256522d268cbSEd Tanous return; 256622d268cbSEd Tanous } 256722d268cbSEd Tanous if (chassisId != "system") 256822d268cbSEd Tanous { 256922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 257022d268cbSEd Tanous return; 257122d268cbSEd Tanous } 257222d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 257322d268cbSEd Tanous } 2574fdd26906SClaire Weinan 2575fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2576fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2577fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2578fdd26906SClaire Weinan const std::string& dumpId) 2579fdd26906SClaire Weinan { 2580fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2581fdd26906SClaire Weinan { 2582fdd26906SClaire Weinan return; 2583fdd26906SClaire Weinan } 2584fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2585fdd26906SClaire Weinan } 2586fdd26906SClaire Weinan 258722d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 258822d268cbSEd Tanous crow::App& app, const crow::Request& req, 258922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 259022d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 259122d268cbSEd Tanous { 259222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 259322d268cbSEd Tanous { 259422d268cbSEd Tanous return; 259522d268cbSEd Tanous } 259622d268cbSEd Tanous if (chassisId != "system") 259722d268cbSEd Tanous { 259822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 259922d268cbSEd Tanous return; 260022d268cbSEd Tanous } 260122d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 260222d268cbSEd Tanous } 260322d268cbSEd Tanous 2604fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2605fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2606fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2607fdd26906SClaire Weinan { 2608fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2609fdd26906SClaire Weinan { 2610fdd26906SClaire Weinan return; 2611fdd26906SClaire Weinan } 2612fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2613fdd26906SClaire Weinan } 2614fdd26906SClaire Weinan 261522d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 261622d268cbSEd Tanous crow::App& app, const crow::Request& req, 261722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 261822d268cbSEd Tanous const std::string& chassisId) 261922d268cbSEd Tanous { 262022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 262122d268cbSEd Tanous { 262222d268cbSEd Tanous return; 262322d268cbSEd Tanous } 262422d268cbSEd Tanous if (chassisId != "system") 262522d268cbSEd Tanous { 262622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 262722d268cbSEd Tanous return; 262822d268cbSEd Tanous } 262922d268cbSEd Tanous createDump(asyncResp, req, "System"); 263022d268cbSEd Tanous } 263122d268cbSEd Tanous 2632fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2633fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2634fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2635fdd26906SClaire Weinan { 2636fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2637fdd26906SClaire Weinan { 2638fdd26906SClaire Weinan return; 2639fdd26906SClaire Weinan } 2640fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2641fdd26906SClaire Weinan } 2642fdd26906SClaire Weinan 264322d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 264422d268cbSEd Tanous crow::App& app, const crow::Request& req, 264522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 264622d268cbSEd Tanous const std::string& chassisId) 264722d268cbSEd Tanous { 264822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 264922d268cbSEd Tanous { 265022d268cbSEd Tanous return; 265122d268cbSEd Tanous } 265222d268cbSEd Tanous if (chassisId != "system") 265322d268cbSEd Tanous { 265422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 265522d268cbSEd Tanous return; 265622d268cbSEd Tanous } 265722d268cbSEd Tanous clearDump(asyncResp, "System"); 265822d268cbSEd Tanous } 265922d268cbSEd Tanous 2660fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2661fdd26906SClaire Weinan { 2662fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2663fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2664fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2665fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2666fdd26906SClaire Weinan } 2667fdd26906SClaire Weinan 2668fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2669fdd26906SClaire Weinan { 2670fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2671fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2672fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2673fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2674c9bb6861Sraviteja-b } 2675c9bb6861Sraviteja-b 26767e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2677c9bb6861Sraviteja-b { 26787e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26797e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2680ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2681fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2682fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2683fdd26906SClaire Weinan 26847e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26857e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2686ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2687fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2688fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2689c9bb6861Sraviteja-b } 2690c9bb6861Sraviteja-b 26917e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2692c9bb6861Sraviteja-b { 26930fda0f12SGeorge Liu BMCWEB_ROUTE( 26940fda0f12SGeorge Liu app, 26950fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2696ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 26977e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2698fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2699fdd26906SClaire Weinan std::ref(app), "BMC")); 2700a43be80fSAsmitha Karunanithi } 2701a43be80fSAsmitha Karunanithi 27027e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 270380319af1SAsmitha Karunanithi { 27040fda0f12SGeorge Liu BMCWEB_ROUTE( 27050fda0f12SGeorge Liu app, 27060fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2707ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2708fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2709fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 271045ca1b86SEd Tanous } 2711fdd26906SClaire Weinan 2712fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2713fdd26906SClaire Weinan { 2714fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2715fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2716fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2717fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2718fdd26906SClaire Weinan } 2719fdd26906SClaire Weinan 2720fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2721fdd26906SClaire Weinan { 2722fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2723fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2724fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2725fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2726fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2727fdd26906SClaire Weinan } 2728fdd26906SClaire Weinan 2729fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2730fdd26906SClaire Weinan { 2731fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2732fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2733fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2734fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2735fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2736fdd26906SClaire Weinan 2737fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2738fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2739fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2740fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2741fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2742fdd26906SClaire Weinan } 2743fdd26906SClaire Weinan 2744fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2745fdd26906SClaire Weinan { 2746fdd26906SClaire Weinan BMCWEB_ROUTE( 2747fdd26906SClaire Weinan app, 2748fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2749fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2750fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2751fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 27525cb1dd27SAsmitha Karunanithi } 27535cb1dd27SAsmitha Karunanithi 27547e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 27555cb1dd27SAsmitha Karunanithi { 275622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2757ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 27586ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 275922d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 27605cb1dd27SAsmitha Karunanithi } 27615cb1dd27SAsmitha Karunanithi 27627e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 27637e860f15SJohn Edward Broadbent { 276422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2765ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 276622d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 276722d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 276822d268cbSEd Tanous std::ref(app))); 27695cb1dd27SAsmitha Karunanithi } 27705cb1dd27SAsmitha Karunanithi 27717e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 27725cb1dd27SAsmitha Karunanithi { 27737e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 277422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2775ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 27766ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 277722d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 27788d1b46d7Szhanghch05 27797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 278022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2781ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 27826ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 278322d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 27845cb1dd27SAsmitha Karunanithi } 2785c9bb6861Sraviteja-b 27867e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2787c9bb6861Sraviteja-b { 27880fda0f12SGeorge Liu BMCWEB_ROUTE( 27890fda0f12SGeorge Liu app, 279022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2791ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 279222d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 279322d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 279422d268cbSEd Tanous std::ref(app))); 2795a43be80fSAsmitha Karunanithi } 2796a43be80fSAsmitha Karunanithi 27977e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2798a43be80fSAsmitha Karunanithi { 27990fda0f12SGeorge Liu BMCWEB_ROUTE( 28000fda0f12SGeorge Liu app, 280122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2802ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28036ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 280422d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2805013487e5Sraviteja-b } 2806013487e5Sraviteja-b 28077e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 28081da66f75SEd Tanous { 28093946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 28103946028dSAppaRao Puli // method for security reasons. 28111da66f75SEd Tanous /** 28121da66f75SEd Tanous * Functions triggers appropriate requests on DBus 28131da66f75SEd Tanous */ 281422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2815ed398213SEd Tanous // This is incorrect, should be: 2816ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2817432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2818002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2819002d39b4SEd Tanous [&app](const crow::Request& req, 282022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 282122d268cbSEd Tanous const std::string& systemName) { 28223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 282345ca1b86SEd Tanous { 282445ca1b86SEd Tanous return; 282545ca1b86SEd Tanous } 282622d268cbSEd Tanous if (systemName != "system") 282722d268cbSEd Tanous { 282822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 282922d268cbSEd Tanous systemName); 283022d268cbSEd Tanous return; 283122d268cbSEd Tanous } 283222d268cbSEd Tanous 28337e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 28347e860f15SJohn Edward Broadbent // SubRoute 28350f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2836424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 2837e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 28388e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 28394f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 28404f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 28414f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 2842e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 2843e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 28447c8c4058STejas Patil 28457c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 28462b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 28477c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 28487c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 28497c8c4058STejas Patil redfishDateTimeOffset.second; 28507c8c4058STejas Patil 28511476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 28521476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 2853002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 28541476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 2855002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 28561476687dSEd Tanous ["target"] = 28571476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 28587e860f15SJohn Edward Broadbent }); 28591da66f75SEd Tanous } 28601da66f75SEd Tanous 28617e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 28625b61b5e8SJason M. Bills { 28630fda0f12SGeorge Liu BMCWEB_ROUTE( 28640fda0f12SGeorge Liu app, 286522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 2866ed398213SEd Tanous // This is incorrect, should be: 2867ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 2868432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 28697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 287045ca1b86SEd Tanous [&app](const crow::Request& req, 287122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 287222d268cbSEd Tanous const std::string& systemName) { 28733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 287445ca1b86SEd Tanous { 287545ca1b86SEd Tanous return; 287645ca1b86SEd Tanous } 287722d268cbSEd Tanous if (systemName != "system") 287822d268cbSEd Tanous { 287922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 288022d268cbSEd Tanous systemName); 288122d268cbSEd Tanous return; 288222d268cbSEd Tanous } 28835b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 28845b61b5e8SJason M. Bills [asyncResp](const boost::system::error_code ec, 2885cb13a392SEd Tanous const std::string&) { 28865b61b5e8SJason M. Bills if (ec) 28875b61b5e8SJason M. Bills { 28885b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 28895b61b5e8SJason M. Bills return; 28905b61b5e8SJason M. Bills } 28915b61b5e8SJason M. Bills messages::success(asyncResp->res); 28925b61b5e8SJason M. Bills }, 2893002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 28947e860f15SJohn Edward Broadbent }); 28955b61b5e8SJason M. Bills } 28965b61b5e8SJason M. Bills 28978d1b46d7Szhanghch05 static void 28988d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 28998d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 2900e855dd28SJason M. Bills { 2901043a0536SJohnathan Mantey auto getStoredLogCallback = 2902b9d36b47SEd Tanous [asyncResp, logID, 2903b9d36b47SEd Tanous &logEntryJson](const boost::system::error_code ec, 2904b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 2905e855dd28SJason M. Bills if (ec) 2906e855dd28SJason M. Bills { 2907e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 29081ddcf01aSJason M. Bills if (ec.value() == 29091ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 29101ddcf01aSJason M. Bills { 2911002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 29121ddcf01aSJason M. Bills } 29131ddcf01aSJason M. Bills else 29141ddcf01aSJason M. Bills { 2915e855dd28SJason M. Bills messages::internalError(asyncResp->res); 29161ddcf01aSJason M. Bills } 2917e855dd28SJason M. Bills return; 2918e855dd28SJason M. Bills } 2919043a0536SJohnathan Mantey 2920043a0536SJohnathan Mantey std::string timestamp{}; 2921043a0536SJohnathan Mantey std::string filename{}; 2922043a0536SJohnathan Mantey std::string logfile{}; 29232c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 2924043a0536SJohnathan Mantey 2925043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 2926e855dd28SJason M. Bills { 2927*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 2928e855dd28SJason M. Bills return; 2929e855dd28SJason M. Bills } 2930e855dd28SJason M. Bills 2931043a0536SJohnathan Mantey std::string crashdumpURI = 2932e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 2933043a0536SJohnathan Mantey logID + "/" + filename; 293484afc48bSJason M. Bills nlohmann::json::object_t logEntry; 29359c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 293684afc48bSJason M. Bills logEntry["@odata.id"] = 293784afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID; 293884afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 293984afc48bSJason M. Bills logEntry["Id"] = logID; 294084afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 294184afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 294284afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 294384afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 294484afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 29452b20ef6eSJason M. Bills 29462b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 29472b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 29482b20ef6eSJason M. Bills // directly 29492b20ef6eSJason M. Bills if (logEntryJson.is_array()) 29502b20ef6eSJason M. Bills { 29512b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 29522b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 29532b20ef6eSJason M. Bills logEntryJson.size(); 29542b20ef6eSJason M. Bills } 29552b20ef6eSJason M. Bills else 29562b20ef6eSJason M. Bills { 2957d405bb51SJason M. Bills logEntryJson.update(logEntry); 29582b20ef6eSJason M. Bills } 2959e855dd28SJason M. Bills }; 2960d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 2961d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 2962d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 2963d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 2964e855dd28SJason M. Bills } 2965e855dd28SJason M. Bills 29667e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 29671da66f75SEd Tanous { 29683946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29693946028dSAppaRao Puli // method for security reasons. 29701da66f75SEd Tanous /** 29711da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29721da66f75SEd Tanous */ 29737e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 297422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 2975ed398213SEd Tanous // This is incorrect, should be. 2976ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 2977432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 2978002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2979002d39b4SEd Tanous [&app](const crow::Request& req, 298022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 298122d268cbSEd Tanous const std::string& systemName) { 29823ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 298345ca1b86SEd Tanous { 298445ca1b86SEd Tanous return; 298545ca1b86SEd Tanous } 298622d268cbSEd Tanous if (systemName != "system") 298722d268cbSEd Tanous { 298822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 298922d268cbSEd Tanous systemName); 299022d268cbSEd Tanous return; 299122d268cbSEd Tanous } 299222d268cbSEd Tanous 29932b20ef6eSJason M. Bills crow::connections::systemBus->async_method_call( 29942b20ef6eSJason M. Bills [asyncResp](const boost::system::error_code ec, 29952b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 29961da66f75SEd Tanous if (ec) 29971da66f75SEd Tanous { 29981da66f75SEd Tanous if (ec.value() != 29991da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 30001da66f75SEd Tanous { 30011da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 30021da66f75SEd Tanous << ec.message(); 3003f12894f8SJason M. Bills messages::internalError(asyncResp->res); 30041da66f75SEd Tanous return; 30051da66f75SEd Tanous } 30061da66f75SEd Tanous } 3007e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 30081da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 30090f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3010424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3011002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3012e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3013424c4176SJason M. Bills "Collection of Crashdump Entries"; 3014002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3015a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 30162b20ef6eSJason M. Bills 30172b20ef6eSJason M. Bills for (const std::string& path : resp) 30181da66f75SEd Tanous { 30192b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3020e855dd28SJason M. Bills // Get the log ID 30212b20ef6eSJason M. Bills std::string logID = objPath.filename(); 30222b20ef6eSJason M. Bills if (logID.empty()) 30231da66f75SEd Tanous { 3024e855dd28SJason M. Bills continue; 30251da66f75SEd Tanous } 3026e855dd28SJason M. Bills // Add the log entry to the array 30272b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 30282b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 30291da66f75SEd Tanous } 30302b20ef6eSJason M. Bills }, 30311da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", 30321da66f75SEd Tanous "/xyz/openbmc_project/object_mapper", 30331da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0, 30345b61b5e8SJason M. Bills std::array<const char*, 1>{crashdumpInterface}); 30357e860f15SJohn Edward Broadbent }); 30361da66f75SEd Tanous } 30371da66f75SEd Tanous 30387e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 30391da66f75SEd Tanous { 30403946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30413946028dSAppaRao Puli // method for security reasons. 30421da66f75SEd Tanous 30437e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 304422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3045ed398213SEd Tanous // this is incorrect, should be 3046ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3047432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 304945ca1b86SEd Tanous [&app](const crow::Request& req, 30507e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 305122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 30523ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 305345ca1b86SEd Tanous { 305445ca1b86SEd Tanous return; 305545ca1b86SEd Tanous } 305622d268cbSEd Tanous if (systemName != "system") 305722d268cbSEd Tanous { 305822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 305922d268cbSEd Tanous systemName); 306022d268cbSEd Tanous ; 306122d268cbSEd Tanous return; 306222d268cbSEd Tanous } 30637e860f15SJohn Edward Broadbent const std::string& logID = param; 3064e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 30657e860f15SJohn Edward Broadbent }); 3066e855dd28SJason M. Bills } 3067e855dd28SJason M. Bills 30687e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3069e855dd28SJason M. Bills { 30703946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 30713946028dSAppaRao Puli // method for security reasons. 30727e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 30737e860f15SJohn Edward Broadbent app, 307422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3075ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 30767e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3077a4ce114aSNan Zhou [](const crow::Request& req, 30787e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 307922d268cbSEd Tanous const std::string& systemName, const std::string& logID, 308022d268cbSEd Tanous const std::string& fileName) { 30812a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 30822a9beeedSShounak Mitra // Redfish resource. 308322d268cbSEd Tanous 308422d268cbSEd Tanous if (systemName != "system") 308522d268cbSEd Tanous { 308622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 308722d268cbSEd Tanous systemName); 308822d268cbSEd Tanous ; 308922d268cbSEd Tanous return; 309022d268cbSEd Tanous } 309122d268cbSEd Tanous 3092043a0536SJohnathan Mantey auto getStoredLogCallback = 3093002d39b4SEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))]( 3094abf2add6SEd Tanous const boost::system::error_code ec, 3095002d39b4SEd Tanous const std::vector< 3096002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 30977e860f15SJohn Edward Broadbent resp) { 30981da66f75SEd Tanous if (ec) 30991da66f75SEd Tanous { 3100002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3101f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31021da66f75SEd Tanous return; 31031da66f75SEd Tanous } 3104e855dd28SJason M. Bills 3105043a0536SJohnathan Mantey std::string dbusFilename{}; 3106043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3107043a0536SJohnathan Mantey std::string dbusFilepath{}; 3108043a0536SJohnathan Mantey 3109002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3110002d39b4SEd Tanous dbusFilepath); 3111043a0536SJohnathan Mantey 3112043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3113043a0536SJohnathan Mantey dbusFilepath.empty()) 31141da66f75SEd Tanous { 3115*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 31161da66f75SEd Tanous return; 31171da66f75SEd Tanous } 3118e855dd28SJason M. Bills 3119043a0536SJohnathan Mantey // Verify the file name parameter is correct 3120043a0536SJohnathan Mantey if (fileName != dbusFilename) 3121043a0536SJohnathan Mantey { 3122*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3123043a0536SJohnathan Mantey return; 3124043a0536SJohnathan Mantey } 3125043a0536SJohnathan Mantey 3126043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3127043a0536SJohnathan Mantey { 3128*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3129043a0536SJohnathan Mantey return; 3130043a0536SJohnathan Mantey } 3131002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3132002d39b4SEd Tanous asyncResp->res.body() = 3133002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3134043a0536SJohnathan Mantey 31357e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 31367e860f15SJohn Edward Broadbent // from a browser 3137d9f6c621SEd Tanous asyncResp->res.addHeader( 3138d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 31391da66f75SEd Tanous }; 3140d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3141d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3142d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3143d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 31447e860f15SJohn Edward Broadbent }); 31451da66f75SEd Tanous } 31461da66f75SEd Tanous 3147c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3148c5a4c82aSJason M. Bills { 3149c5a4c82aSJason M. Bills onDemand, 3150c5a4c82aSJason M. Bills telemetry, 3151c5a4c82aSJason M. Bills invalid, 3152c5a4c82aSJason M. Bills }; 3153c5a4c82aSJason M. Bills 3154f7725d79SEd Tanous inline OEMDiagnosticType 3155f7725d79SEd Tanous getOEMDiagnosticType(const std::string_view& oemDiagStr) 3156c5a4c82aSJason M. Bills { 3157c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3158c5a4c82aSJason M. Bills { 3159c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3160c5a4c82aSJason M. Bills } 3161c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3162c5a4c82aSJason M. Bills { 3163c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3164c5a4c82aSJason M. Bills } 3165c5a4c82aSJason M. Bills 3166c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3167c5a4c82aSJason M. Bills } 3168c5a4c82aSJason M. Bills 31697e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 31701da66f75SEd Tanous { 31713946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31723946028dSAppaRao Puli // method for security reasons. 31730fda0f12SGeorge Liu BMCWEB_ROUTE( 31740fda0f12SGeorge Liu app, 317522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3176ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3177ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3178432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3179002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3180002d39b4SEd Tanous [&app](const crow::Request& req, 318122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 318222d268cbSEd Tanous const std::string& systemName) { 31833ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 318445ca1b86SEd Tanous { 318545ca1b86SEd Tanous return; 318645ca1b86SEd Tanous } 318722d268cbSEd Tanous 318822d268cbSEd Tanous if (systemName != "system") 318922d268cbSEd Tanous { 319022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 319122d268cbSEd Tanous systemName); 319222d268cbSEd Tanous ; 319322d268cbSEd Tanous return; 319422d268cbSEd Tanous } 319522d268cbSEd Tanous 31968e6c099aSJason M. Bills std::string diagnosticDataType; 31978e6c099aSJason M. Bills std::string oemDiagnosticDataType; 319815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3199002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3200002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 32018e6c099aSJason M. Bills { 32028e6c099aSJason M. Bills return; 32038e6c099aSJason M. Bills } 32048e6c099aSJason M. Bills 32058e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 32068e6c099aSJason M. Bills { 32078e6c099aSJason M. Bills BMCWEB_LOG_ERROR 32088e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 32098e6c099aSJason M. Bills messages::actionParameterValueFormatError( 32108e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 32118e6c099aSJason M. Bills "CollectDiagnosticData"); 32128e6c099aSJason M. Bills return; 32138e6c099aSJason M. Bills } 32148e6c099aSJason M. Bills 3215c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3216c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3217c5a4c82aSJason M. Bills 3218c5a4c82aSJason M. Bills std::string iface; 3219c5a4c82aSJason M. Bills std::string method; 3220c5a4c82aSJason M. Bills std::string taskMatchStr; 3221c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3222c5a4c82aSJason M. Bills { 3223c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3224c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3225c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3226c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3227c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3228c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3229c5a4c82aSJason M. Bills } 3230c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3231c5a4c82aSJason M. Bills { 3232c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3233c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3234c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3235c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3236c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3237c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3238c5a4c82aSJason M. Bills } 3239c5a4c82aSJason M. Bills else 3240c5a4c82aSJason M. Bills { 3241c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3242c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3243c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3244002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3245002d39b4SEd Tanous "CollectDiagnosticData"); 3246c5a4c82aSJason M. Bills return; 3247c5a4c82aSJason M. Bills } 3248c5a4c82aSJason M. Bills 3249c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3250c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 3251c5a4c82aSJason M. Bills taskMatchStr](const boost::system::error_code ec, 325298be3e39SEd Tanous const std::string&) mutable { 32531da66f75SEd Tanous if (ec) 32541da66f75SEd Tanous { 3255002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 32561da66f75SEd Tanous { 3257f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 32581da66f75SEd Tanous } 32594363d3b2SJason M. Bills else if (ec.value() == 32604363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 32614363d3b2SJason M. Bills { 3262002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3263002d39b4SEd Tanous "60"); 32644363d3b2SJason M. Bills } 32651da66f75SEd Tanous else 32661da66f75SEd Tanous { 3267f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32681da66f75SEd Tanous } 32691da66f75SEd Tanous return; 32701da66f75SEd Tanous } 3271002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 327259d494eeSPatrick Williams [](boost::system::error_code err, sdbusplus::message_t&, 3273002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 327466afe4faSJames Feist if (!err) 327566afe4faSJames Feist { 3276002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3277e5d5006bSJames Feist std::to_string(taskData->index))); 3278831d6b09SJames Feist taskData->state = "Completed"; 327966afe4faSJames Feist } 328032898ceaSJames Feist return task::completed; 328166afe4faSJames Feist }, 3282c5a4c82aSJason M. Bills taskMatchStr); 3283c5a4c82aSJason M. Bills 328446229577SJames Feist task->startTimer(std::chrono::minutes(5)); 328546229577SJames Feist task->populateResp(asyncResp->res); 328698be3e39SEd Tanous task->payload.emplace(std::move(payload)); 32871da66f75SEd Tanous }; 32888e6c099aSJason M. Bills 32891da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3290002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3291002d39b4SEd Tanous iface, method); 32927e860f15SJohn Edward Broadbent }); 32936eda7685SKenny L. Ku } 32946eda7685SKenny L. Ku 3295cb92c03bSAndrew Geissler /** 3296cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3297cb92c03bSAndrew Geissler */ 32987e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3299cb92c03bSAndrew Geissler { 3300cb92c03bSAndrew Geissler /** 3301cb92c03bSAndrew Geissler * Function handles POST method request. 3302cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3303cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3304cb92c03bSAndrew Geissler */ 33057e860f15SJohn Edward Broadbent 33060fda0f12SGeorge Liu BMCWEB_ROUTE( 33070fda0f12SGeorge Liu app, 330822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3309ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 33107e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 331145ca1b86SEd Tanous [&app](const crow::Request& req, 331222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 331322d268cbSEd Tanous const std::string& systemName) { 33143ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 331545ca1b86SEd Tanous { 331645ca1b86SEd Tanous return; 331745ca1b86SEd Tanous } 331822d268cbSEd Tanous if (systemName != "system") 331922d268cbSEd Tanous { 332022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 332122d268cbSEd Tanous systemName); 332222d268cbSEd Tanous ; 332322d268cbSEd Tanous return; 332422d268cbSEd Tanous } 3325cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3326cb92c03bSAndrew Geissler 3327cb92c03bSAndrew Geissler // Process response from Logging service. 3328002d39b4SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code ec) { 3329002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3330cb92c03bSAndrew Geissler if (ec) 3331cb92c03bSAndrew Geissler { 3332cb92c03bSAndrew Geissler // TODO Handle for specific error code 3333002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3334cb92c03bSAndrew Geissler asyncResp->res.result( 3335cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3336cb92c03bSAndrew Geissler return; 3337cb92c03bSAndrew Geissler } 3338cb92c03bSAndrew Geissler 3339002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3340cb92c03bSAndrew Geissler }; 3341cb92c03bSAndrew Geissler 3342cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3343cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 33442c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3345cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3346cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 33477e860f15SJohn Edward Broadbent }); 3348cb92c03bSAndrew Geissler } 3349a3316fc6SZhikuiRen 3350a3316fc6SZhikuiRen /**************************************************** 3351a3316fc6SZhikuiRen * Redfish PostCode interfaces 3352a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3353a3316fc6SZhikuiRen ******************************************************/ 33547e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3355a3316fc6SZhikuiRen { 335622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3357ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3358002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3359002d39b4SEd Tanous [&app](const crow::Request& req, 336022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 336122d268cbSEd Tanous const std::string& systemName) { 33623ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 336345ca1b86SEd Tanous { 336445ca1b86SEd Tanous return; 336545ca1b86SEd Tanous } 336622d268cbSEd Tanous if (systemName != "system") 336722d268cbSEd Tanous { 336822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 336922d268cbSEd Tanous systemName); 337022d268cbSEd Tanous ; 337122d268cbSEd Tanous return; 337222d268cbSEd Tanous } 33731476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 33741476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 33751476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 33761476687dSEd Tanous "#LogService.v1_1_0.LogService"; 33771476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 33781476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 33791476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log"; 33801476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 33811476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 33821476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 33837c8c4058STejas Patil 33847c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 33852b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 33860fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 33877c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 33887c8c4058STejas Patil redfishDateTimeOffset.second; 33897c8c4058STejas Patil 3390a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 33917e860f15SJohn Edward Broadbent {"target", 33920fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 33937e860f15SJohn Edward Broadbent }); 3394a3316fc6SZhikuiRen } 3395a3316fc6SZhikuiRen 33967e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3397a3316fc6SZhikuiRen { 33980fda0f12SGeorge Liu BMCWEB_ROUTE( 33990fda0f12SGeorge Liu app, 340022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3401ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3402ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3403432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 34047e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 340545ca1b86SEd Tanous [&app](const crow::Request& req, 340622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 340722d268cbSEd Tanous const std::string& systemName) { 34083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 340945ca1b86SEd Tanous { 341045ca1b86SEd Tanous return; 341145ca1b86SEd Tanous } 341222d268cbSEd Tanous if (systemName != "system") 341322d268cbSEd Tanous { 341422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 341522d268cbSEd Tanous systemName); 341622d268cbSEd Tanous ; 341722d268cbSEd Tanous return; 341822d268cbSEd Tanous } 3419a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3420a3316fc6SZhikuiRen 3421a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3422a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3423a3316fc6SZhikuiRen [asyncResp](const boost::system::error_code ec) { 3424a3316fc6SZhikuiRen if (ec) 3425a3316fc6SZhikuiRen { 3426a3316fc6SZhikuiRen // TODO Handle for specific error code 3427002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 34287e860f15SJohn Edward Broadbent << ec; 3429002d39b4SEd Tanous asyncResp->res.result( 3430002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3431a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3432a3316fc6SZhikuiRen return; 3433a3316fc6SZhikuiRen } 3434a3316fc6SZhikuiRen }, 343515124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 343615124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3437a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 34387e860f15SJohn Edward Broadbent }); 3439a3316fc6SZhikuiRen } 3440a3316fc6SZhikuiRen 3441a3316fc6SZhikuiRen static void fillPostCodeEntry( 34428d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 34436c9a279eSManojkiran Eda const boost::container::flat_map< 34446c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3445a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3446a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3447a3316fc6SZhikuiRen { 3448a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3449fffb8c1fSEd Tanous const registries::Message* message = 3450fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3451a3316fc6SZhikuiRen 3452a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3453a3316fc6SZhikuiRen nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 3454a3316fc6SZhikuiRen 3455a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 34566c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 34576c9a279eSManojkiran Eda code : postcode) 3458a3316fc6SZhikuiRen { 3459a3316fc6SZhikuiRen currentCodeIndex++; 3460a3316fc6SZhikuiRen std::string postcodeEntryID = 3461a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3462a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3463a3316fc6SZhikuiRen 3464a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3465a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3466a3316fc6SZhikuiRen 3467a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3468a3316fc6SZhikuiRen { // already incremented 3469a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3470a3316fc6SZhikuiRen } 3471a3316fc6SZhikuiRen else 3472a3316fc6SZhikuiRen { 3473a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3474a3316fc6SZhikuiRen } 3475a3316fc6SZhikuiRen 3476a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3477a3316fc6SZhikuiRen // not fall between top and skip 3478a3316fc6SZhikuiRen if ((codeIndex == 0) && 3479a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3480a3316fc6SZhikuiRen { 3481a3316fc6SZhikuiRen continue; 3482a3316fc6SZhikuiRen } 3483a3316fc6SZhikuiRen 34844e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3485a3316fc6SZhikuiRen // currentIndex 3486a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3487a3316fc6SZhikuiRen { 3488a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3489a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3490a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3491a3316fc6SZhikuiRen continue; 3492a3316fc6SZhikuiRen } 3493a3316fc6SZhikuiRen 3494a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3495a3316fc6SZhikuiRen // index 3496a3316fc6SZhikuiRen 3497a3316fc6SZhikuiRen // Get the Created time from the timestamp 3498a3316fc6SZhikuiRen std::string entryTimeStr; 34991d8782e7SNan Zhou entryTimeStr = 35002b82937eSEd Tanous redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000); 3501a3316fc6SZhikuiRen 3502a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3503a3316fc6SZhikuiRen std::ostringstream hexCode; 3504a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 35056c9a279eSManojkiran Eda << std::get<0>(code.second); 3506a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3507a3316fc6SZhikuiRen // Set Fixed -Point Notation 3508a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3509a3316fc6SZhikuiRen // Set precision to 4 digits 3510a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3511a3316fc6SZhikuiRen // Add double to stream 3512a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3513a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3514a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3515a3316fc6SZhikuiRen 3516a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3517a3316fc6SZhikuiRen std::string msg; 3518a3316fc6SZhikuiRen if (message != nullptr) 3519a3316fc6SZhikuiRen { 3520a3316fc6SZhikuiRen msg = message->message; 3521a3316fc6SZhikuiRen 3522a3316fc6SZhikuiRen // fill in this post code value 3523a3316fc6SZhikuiRen int i = 0; 3524a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3525a3316fc6SZhikuiRen { 3526a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3527a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3528a3316fc6SZhikuiRen if (argPos != std::string::npos) 3529a3316fc6SZhikuiRen { 3530a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3531a3316fc6SZhikuiRen } 3532a3316fc6SZhikuiRen } 3533a3316fc6SZhikuiRen } 3534a3316fc6SZhikuiRen 3535d4342a92STim Lee // Get Severity template from message registry 3536d4342a92STim Lee std::string severity; 3537d4342a92STim Lee if (message != nullptr) 3538d4342a92STim Lee { 35395f2b84eeSEd Tanous severity = message->messageSeverity; 3540d4342a92STim Lee } 3541d4342a92STim Lee 3542a3316fc6SZhikuiRen // add to AsyncResp 3543a3316fc6SZhikuiRen logEntryArray.push_back({}); 3544a3316fc6SZhikuiRen nlohmann::json& bmcLogEntry = logEntryArray.back(); 35459c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 354684afc48bSJason M. Bills bmcLogEntry["@odata.id"] = 35470fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 354884afc48bSJason M. Bills postcodeEntryID; 354984afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 355084afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 355184afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 355284afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 355384afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 355484afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 355584afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 355684afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3557647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3558647b3cdcSGeorge Liu { 3559647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3560647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3561647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3562647b3cdcSGeorge Liu } 3563a3316fc6SZhikuiRen } 3564a3316fc6SZhikuiRen } 3565a3316fc6SZhikuiRen 35668d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3567a3316fc6SZhikuiRen const uint16_t bootIndex, 3568a3316fc6SZhikuiRen const uint64_t codeIndex) 3569a3316fc6SZhikuiRen { 3570a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 35716c9a279eSManojkiran Eda [aResp, bootIndex, 35726c9a279eSManojkiran Eda codeIndex](const boost::system::error_code ec, 35736c9a279eSManojkiran Eda const boost::container::flat_map< 35746c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 35756c9a279eSManojkiran Eda postcode) { 3576a3316fc6SZhikuiRen if (ec) 3577a3316fc6SZhikuiRen { 3578a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3579a3316fc6SZhikuiRen messages::internalError(aResp->res); 3580a3316fc6SZhikuiRen return; 3581a3316fc6SZhikuiRen } 3582a3316fc6SZhikuiRen 3583a3316fc6SZhikuiRen // skip the empty postcode boots 3584a3316fc6SZhikuiRen if (postcode.empty()) 3585a3316fc6SZhikuiRen { 3586a3316fc6SZhikuiRen return; 3587a3316fc6SZhikuiRen } 3588a3316fc6SZhikuiRen 3589a3316fc6SZhikuiRen fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex); 3590a3316fc6SZhikuiRen 3591a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = 3592a3316fc6SZhikuiRen aResp->res.jsonValue["Members"].size(); 3593a3316fc6SZhikuiRen }, 359415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 359515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3596a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3597a3316fc6SZhikuiRen bootIndex); 3598a3316fc6SZhikuiRen } 3599a3316fc6SZhikuiRen 36008d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3601a3316fc6SZhikuiRen const uint16_t bootIndex, 3602a3316fc6SZhikuiRen const uint16_t bootCount, 36033648c8beSEd Tanous const uint64_t entryCount, size_t skip, 36043648c8beSEd Tanous size_t top) 3605a3316fc6SZhikuiRen { 3606a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3607a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 3608a3316fc6SZhikuiRen top](const boost::system::error_code ec, 36096c9a279eSManojkiran Eda const boost::container::flat_map< 36106c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36116c9a279eSManojkiran Eda postcode) { 3612a3316fc6SZhikuiRen if (ec) 3613a3316fc6SZhikuiRen { 3614a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3615a3316fc6SZhikuiRen messages::internalError(aResp->res); 3616a3316fc6SZhikuiRen return; 3617a3316fc6SZhikuiRen } 3618a3316fc6SZhikuiRen 3619a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3620a3316fc6SZhikuiRen if (!postcode.empty()) 3621a3316fc6SZhikuiRen { 3622a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 36233648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3624a3316fc6SZhikuiRen { 36253648c8beSEd Tanous uint64_t thisBootSkip = 36263648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 36273648c8beSEd Tanous entryCount; 3628a3316fc6SZhikuiRen uint64_t thisBootTop = 36293648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 36303648c8beSEd Tanous entryCount; 3631a3316fc6SZhikuiRen 3632002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3633002d39b4SEd Tanous thisBootTop); 3634a3316fc6SZhikuiRen } 3635a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3636a3316fc6SZhikuiRen } 3637a3316fc6SZhikuiRen 3638a3316fc6SZhikuiRen // continue to previous bootIndex 3639a3316fc6SZhikuiRen if (bootIndex < bootCount) 3640a3316fc6SZhikuiRen { 3641a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3642a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3643a3316fc6SZhikuiRen } 364481584abeSJiaqing Zhao else if (skip + top < endCount) 3645a3316fc6SZhikuiRen { 3646a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 36470fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3648a3316fc6SZhikuiRen std::to_string(skip + top); 3649a3316fc6SZhikuiRen } 3650a3316fc6SZhikuiRen }, 365115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 365215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3653a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3654a3316fc6SZhikuiRen bootIndex); 3655a3316fc6SZhikuiRen } 3656a3316fc6SZhikuiRen 36578d1b46d7Szhanghch05 static void 36588d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 36593648c8beSEd Tanous size_t skip, size_t top) 3660a3316fc6SZhikuiRen { 3661a3316fc6SZhikuiRen uint64_t entryCount = 0; 36621e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 36631e1e598dSJonathan Doman *crow::connections::systemBus, 36641e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 36651e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 36661e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 36671e1e598dSJonathan Doman [aResp, entryCount, skip, top](const boost::system::error_code ec, 36681e1e598dSJonathan Doman const uint16_t bootCount) { 3669a3316fc6SZhikuiRen if (ec) 3670a3316fc6SZhikuiRen { 3671a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3672a3316fc6SZhikuiRen messages::internalError(aResp->res); 3673a3316fc6SZhikuiRen return; 3674a3316fc6SZhikuiRen } 36751e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 36761e1e598dSJonathan Doman }); 3677a3316fc6SZhikuiRen } 3678a3316fc6SZhikuiRen 36797e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3680a3316fc6SZhikuiRen { 36817e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 368222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3683ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 36847e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 368545ca1b86SEd Tanous [&app](const crow::Request& req, 368622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 368722d268cbSEd Tanous const std::string& systemName) { 3688c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3689c937d2bfSEd Tanous .canDelegateTop = true, 3690c937d2bfSEd Tanous .canDelegateSkip = true, 3691c937d2bfSEd Tanous }; 3692c937d2bfSEd Tanous query_param::Query delegatedQuery; 3693c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 36943ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 369545ca1b86SEd Tanous { 369645ca1b86SEd Tanous return; 369745ca1b86SEd Tanous } 369822d268cbSEd Tanous 369922d268cbSEd Tanous if (systemName != "system") 370022d268cbSEd Tanous { 370122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 370222d268cbSEd Tanous systemName); 370322d268cbSEd Tanous ; 370422d268cbSEd Tanous return; 370522d268cbSEd Tanous } 3706a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3707a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3708a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3709a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3710a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3711a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3712a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3713a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3714a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 37153648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 37165143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 37173648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 37187e860f15SJohn Edward Broadbent }); 3719a3316fc6SZhikuiRen } 3720a3316fc6SZhikuiRen 3721647b3cdcSGeorge Liu /** 3722647b3cdcSGeorge Liu * @brief Parse post code ID and get the current value and index value 3723647b3cdcSGeorge Liu * eg: postCodeID=B1-2, currentValue=1, index=2 3724647b3cdcSGeorge Liu * 3725647b3cdcSGeorge Liu * @param[in] postCodeID Post Code ID 3726647b3cdcSGeorge Liu * @param[out] currentValue Current value 3727647b3cdcSGeorge Liu * @param[out] index Index value 3728647b3cdcSGeorge Liu * 3729647b3cdcSGeorge Liu * @return bool true if the parsing is successful, false the parsing fails 3730647b3cdcSGeorge Liu */ 3731647b3cdcSGeorge Liu inline static bool parsePostCode(const std::string& postCodeID, 3732647b3cdcSGeorge Liu uint64_t& currentValue, uint16_t& index) 3733647b3cdcSGeorge Liu { 3734647b3cdcSGeorge Liu std::vector<std::string> split; 3735647b3cdcSGeorge Liu boost::algorithm::split(split, postCodeID, boost::is_any_of("-")); 3736647b3cdcSGeorge Liu if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 3737647b3cdcSGeorge Liu { 3738647b3cdcSGeorge Liu return false; 3739647b3cdcSGeorge Liu } 3740647b3cdcSGeorge Liu 3741ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3742647b3cdcSGeorge Liu const char* start = split[0].data() + 1; 3743ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3744647b3cdcSGeorge Liu const char* end = split[0].data() + split[0].size(); 3745647b3cdcSGeorge Liu auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 3746647b3cdcSGeorge Liu 3747647b3cdcSGeorge Liu if (ptrIndex != end || ecIndex != std::errc()) 3748647b3cdcSGeorge Liu { 3749647b3cdcSGeorge Liu return false; 3750647b3cdcSGeorge Liu } 3751647b3cdcSGeorge Liu 3752647b3cdcSGeorge Liu start = split[1].data(); 3753ca45aa3cSEd Tanous 3754ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 3755647b3cdcSGeorge Liu end = split[1].data() + split[1].size(); 3756647b3cdcSGeorge Liu auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 3757647b3cdcSGeorge Liu 3758517d9a58STony Lee return ptrValue == end && ecValue == std::errc(); 3759647b3cdcSGeorge Liu } 3760647b3cdcSGeorge Liu 3761647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3762647b3cdcSGeorge Liu { 37630fda0f12SGeorge Liu BMCWEB_ROUTE( 37640fda0f12SGeorge Liu app, 376522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3766647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3767647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 376845ca1b86SEd Tanous [&app](const crow::Request& req, 3769647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 377022d268cbSEd Tanous const std::string& systemName, 3771647b3cdcSGeorge Liu const std::string& postCodeID) { 37723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 377345ca1b86SEd Tanous { 377445ca1b86SEd Tanous return; 377545ca1b86SEd Tanous } 377699351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 377799351cd8SEd Tanous req.getHeaderValue("Accept"), 37784a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3779647b3cdcSGeorge Liu { 3780002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3781647b3cdcSGeorge Liu return; 3782647b3cdcSGeorge Liu } 378322d268cbSEd Tanous if (systemName != "system") 378422d268cbSEd Tanous { 378522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 378622d268cbSEd Tanous systemName); 378722d268cbSEd Tanous ; 378822d268cbSEd Tanous return; 378922d268cbSEd Tanous } 3790647b3cdcSGeorge Liu 3791647b3cdcSGeorge Liu uint64_t currentValue = 0; 3792647b3cdcSGeorge Liu uint16_t index = 0; 3793647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3794647b3cdcSGeorge Liu { 3795002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3796647b3cdcSGeorge Liu return; 3797647b3cdcSGeorge Liu } 3798647b3cdcSGeorge Liu 3799647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3800647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 3801647b3cdcSGeorge Liu const boost::system::error_code ec, 3802002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 3803002d39b4SEd Tanous postcodes) { 3804647b3cdcSGeorge Liu if (ec.value() == EBADR) 3805647b3cdcSGeorge Liu { 3806002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3807002d39b4SEd Tanous postCodeID); 3808647b3cdcSGeorge Liu return; 3809647b3cdcSGeorge Liu } 3810647b3cdcSGeorge Liu if (ec) 3811647b3cdcSGeorge Liu { 3812647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3813647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 3814647b3cdcSGeorge Liu return; 3815647b3cdcSGeorge Liu } 3816647b3cdcSGeorge Liu 3817647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 3818002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 3819647b3cdcSGeorge Liu { 3820647b3cdcSGeorge Liu BMCWEB_LOG_ERROR << "Wrong currentValue value"; 3821002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3822002d39b4SEd Tanous postCodeID); 3823647b3cdcSGeorge Liu return; 3824647b3cdcSGeorge Liu } 3825647b3cdcSGeorge Liu 38269eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 382746ff87baSEd Tanous if (c.empty()) 3828647b3cdcSGeorge Liu { 3829647b3cdcSGeorge Liu BMCWEB_LOG_INFO << "No found post code data"; 3830002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3831002d39b4SEd Tanous postCodeID); 3832647b3cdcSGeorge Liu return; 3833647b3cdcSGeorge Liu } 383446ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 383546ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 383646ff87baSEd Tanous std::string_view strData(d, c.size()); 3837647b3cdcSGeorge Liu 3838d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 3839647b3cdcSGeorge Liu "application/octet-stream"); 3840d9f6c621SEd Tanous asyncResp->res.addHeader( 3841d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 3842002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 3843647b3cdcSGeorge Liu }, 3844647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 3845647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 3846002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 3847647b3cdcSGeorge Liu }); 3848647b3cdcSGeorge Liu } 3849647b3cdcSGeorge Liu 38507e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 3851a3316fc6SZhikuiRen { 38527e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 385322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 3854ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 38557e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 385645ca1b86SEd Tanous [&app](const crow::Request& req, 38577e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 385822d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 38593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 386045ca1b86SEd Tanous { 386145ca1b86SEd Tanous return; 386245ca1b86SEd Tanous } 386322d268cbSEd Tanous if (systemName != "system") 386422d268cbSEd Tanous { 386522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 386622d268cbSEd Tanous systemName); 386722d268cbSEd Tanous return; 386822d268cbSEd Tanous } 386922d268cbSEd Tanous 3870647b3cdcSGeorge Liu uint16_t bootIndex = 0; 3871647b3cdcSGeorge Liu uint64_t codeIndex = 0; 3872647b3cdcSGeorge Liu if (!parsePostCode(targetID, codeIndex, bootIndex)) 3873a3316fc6SZhikuiRen { 3874a3316fc6SZhikuiRen // Requested ID was not found 3875*9db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 3876a3316fc6SZhikuiRen return; 3877a3316fc6SZhikuiRen } 3878a3316fc6SZhikuiRen if (bootIndex == 0 || codeIndex == 0) 3879a3316fc6SZhikuiRen { 3880a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string " 38817e860f15SJohn Edward Broadbent << targetID; 3882a3316fc6SZhikuiRen } 3883a3316fc6SZhikuiRen 38849c11a172SVijay Lobo asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3885a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 38860fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3887a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3888a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3889a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3890a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3891a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 3892a3316fc6SZhikuiRen 3893a3316fc6SZhikuiRen getPostCodeForEntry(asyncResp, bootIndex, codeIndex); 38947e860f15SJohn Edward Broadbent }); 3895a3316fc6SZhikuiRen } 3896a3316fc6SZhikuiRen 38971da66f75SEd Tanous } // namespace redfish 3898