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 18*7a1dbc48SGeorge Liu #include "dbus_utility.hpp" 19b7028ebfSSpencer Ku #include "gzfile.hpp" 20647b3cdcSGeorge Liu #include "http_utility.hpp" 21b7028ebfSSpencer Ku #include "human_sort.hpp" 224851d45dSJason M. Bills #include "registries.hpp" 234851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 244851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 2546229577SJames Feist #include "task.hpp" 261da66f75SEd Tanous 27e1f26343SJason M. Bills #include <systemd/sd-journal.h> 288e31778eSAsmitha Karunanithi #include <tinyxml2.h> 29400fd1fbSAdriana Kobylak #include <unistd.h> 30e1f26343SJason M. Bills 317e860f15SJohn Edward Broadbent #include <app.hpp> 329896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 3311ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 34400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 354851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 3607c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 371da66f75SEd Tanous #include <boost/container/flat_map.hpp> 381ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 39cb92c03bSAndrew Geissler #include <error_messages.hpp> 4045ca1b86SEd Tanous #include <query.hpp> 41ed398213SEd Tanous #include <registries/privilege_registry.hpp> 42d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 43d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 44d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp> 452b82937eSEd Tanous #include <utils/time_utils.hpp> 461214b7e7SGunnar Mills 47*7a1dbc48SGeorge Liu #include <array> 48647b3cdcSGeorge Liu #include <charconv> 494418c7f0SJames Feist #include <filesystem> 5075710de2SXiaochao Ma #include <optional> 5126702d01SEd Tanous #include <span> 52cd225da8SJason M. Bills #include <string_view> 53abf2add6SEd Tanous #include <variant> 541da66f75SEd Tanous 551da66f75SEd Tanous namespace redfish 561da66f75SEd Tanous { 571da66f75SEd Tanous 585b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump"; 595b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump"; 605b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump"; 615b61b5e8SJason M. Bills constexpr char const* deleteAllInterface = 625b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 635b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface = 64424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 656eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface = 666eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 671da66f75SEd Tanous 688e31778eSAsmitha Karunanithi enum class DumpCreationProgress 698e31778eSAsmitha Karunanithi { 708e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 718e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 728e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 738e31778eSAsmitha Karunanithi }; 748e31778eSAsmitha Karunanithi 75fffb8c1fSEd Tanous namespace registries 764851d45dSJason M. Bills { 7726702d01SEd Tanous static const Message* 7826702d01SEd Tanous getMessageFromRegistry(const std::string& messageKey, 7926702d01SEd Tanous const std::span<const MessageEntry> registry) 804851d45dSJason M. Bills { 81002d39b4SEd Tanous std::span<const MessageEntry>::iterator messageIt = 82002d39b4SEd Tanous std::find_if(registry.begin(), registry.end(), 834851d45dSJason M. Bills [&messageKey](const MessageEntry& messageEntry) { 84e662eae8SEd Tanous return std::strcmp(messageEntry.first, messageKey.c_str()) == 0; 854851d45dSJason M. Bills }); 8626702d01SEd Tanous if (messageIt != registry.end()) 874851d45dSJason M. Bills { 884851d45dSJason M. Bills return &messageIt->second; 894851d45dSJason M. Bills } 904851d45dSJason M. Bills 914851d45dSJason M. Bills return nullptr; 924851d45dSJason M. Bills } 934851d45dSJason M. Bills 944851d45dSJason M. Bills static const Message* getMessage(const std::string_view& messageID) 954851d45dSJason M. Bills { 964851d45dSJason M. Bills // Redfish MessageIds are in the form 974851d45dSJason M. Bills // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find 984851d45dSJason M. Bills // the right Message 994851d45dSJason M. Bills std::vector<std::string> fields; 1004851d45dSJason M. Bills fields.reserve(4); 1014851d45dSJason M. Bills boost::split(fields, messageID, boost::is_any_of(".")); 10202cad96eSEd Tanous const std::string& registryName = fields[0]; 10302cad96eSEd Tanous const std::string& messageKey = fields[3]; 1044851d45dSJason M. Bills 1054851d45dSJason M. Bills // Find the right registry and check it for the MessageKey 1064851d45dSJason M. Bills if (std::string(base::header.registryPrefix) == registryName) 1074851d45dSJason M. Bills { 1084851d45dSJason M. Bills return getMessageFromRegistry( 10926702d01SEd Tanous messageKey, std::span<const MessageEntry>(base::registry)); 1104851d45dSJason M. Bills } 1114851d45dSJason M. Bills if (std::string(openbmc::header.registryPrefix) == registryName) 1124851d45dSJason M. Bills { 1134851d45dSJason M. Bills return getMessageFromRegistry( 11426702d01SEd Tanous messageKey, std::span<const MessageEntry>(openbmc::registry)); 1154851d45dSJason M. Bills } 1164851d45dSJason M. Bills return nullptr; 1174851d45dSJason M. Bills } 118fffb8c1fSEd Tanous } // namespace registries 1194851d45dSJason M. Bills 120f6150403SJames Feist namespace fs = std::filesystem; 1211da66f75SEd Tanous 122cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 123cb92c03bSAndrew Geissler { 124d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 125d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 126d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 127d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 128cb92c03bSAndrew Geissler { 129cb92c03bSAndrew Geissler return "Critical"; 130cb92c03bSAndrew Geissler } 1313174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 132d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 133d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 134cb92c03bSAndrew Geissler { 135cb92c03bSAndrew Geissler return "OK"; 136cb92c03bSAndrew Geissler } 1373174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 138cb92c03bSAndrew Geissler { 139cb92c03bSAndrew Geissler return "Warning"; 140cb92c03bSAndrew Geissler } 141cb92c03bSAndrew Geissler return ""; 142cb92c03bSAndrew Geissler } 143cb92c03bSAndrew Geissler 1449017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1459017faf2SAbhishek Patel { 1469017faf2SAbhishek Patel std::optional<bool> notifyAction; 1479017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1489017faf2SAbhishek Patel { 1499017faf2SAbhishek Patel notifyAction = true; 1509017faf2SAbhishek Patel } 1519017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1529017faf2SAbhishek Patel { 1539017faf2SAbhishek Patel notifyAction = false; 1549017faf2SAbhishek Patel } 1559017faf2SAbhishek Patel 1569017faf2SAbhishek Patel return notifyAction; 1579017faf2SAbhishek Patel } 1589017faf2SAbhishek Patel 1597e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 16039e77504SEd Tanous const std::string_view& field, 16139e77504SEd Tanous std::string_view& contents) 16216428a1aSJason M. Bills { 16316428a1aSJason M. Bills const char* data = nullptr; 16416428a1aSJason M. Bills size_t length = 0; 16516428a1aSJason M. Bills int ret = 0; 16616428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 16746ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 16846ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 16946ff87baSEd Tanous 17046ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 17116428a1aSJason M. Bills if (ret < 0) 17216428a1aSJason M. Bills { 17316428a1aSJason M. Bills return ret; 17416428a1aSJason M. Bills } 17539e77504SEd Tanous contents = std::string_view(data, length); 17616428a1aSJason M. Bills // Only use the content after the "=" character. 17781ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 17816428a1aSJason M. Bills return ret; 17916428a1aSJason M. Bills } 18016428a1aSJason M. Bills 1817e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 1827e860f15SJohn Edward Broadbent const std::string_view& field, 1837e860f15SJohn Edward Broadbent const int& base, long int& contents) 18416428a1aSJason M. Bills { 18516428a1aSJason M. Bills int ret = 0; 18639e77504SEd Tanous std::string_view metadata; 18716428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 18816428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 18916428a1aSJason M. Bills if (ret < 0) 19016428a1aSJason M. Bills { 19116428a1aSJason M. Bills return ret; 19216428a1aSJason M. Bills } 193b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 19416428a1aSJason M. Bills return ret; 19516428a1aSJason M. Bills } 19616428a1aSJason M. Bills 1977e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1987e860f15SJohn Edward Broadbent std::string& entryTimestamp) 199a3316fc6SZhikuiRen { 200a3316fc6SZhikuiRen int ret = 0; 201a3316fc6SZhikuiRen uint64_t timestamp = 0; 202a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 203a3316fc6SZhikuiRen if (ret < 0) 204a3316fc6SZhikuiRen { 205a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 206a3316fc6SZhikuiRen << strerror(-ret); 207a3316fc6SZhikuiRen return false; 208a3316fc6SZhikuiRen } 2092b82937eSEd Tanous entryTimestamp = 2102b82937eSEd Tanous redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000); 2119c620e21SAsmitha Karunanithi return true; 212a3316fc6SZhikuiRen } 21350b8a43aSEd Tanous 2147e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 215e85d6b16SJason M. Bills const bool firstEntry = true) 21616428a1aSJason M. Bills { 21716428a1aSJason M. Bills int ret = 0; 21816428a1aSJason M. Bills static uint64_t prevTs = 0; 21916428a1aSJason M. Bills static int index = 0; 220e85d6b16SJason M. Bills if (firstEntry) 221e85d6b16SJason M. Bills { 222e85d6b16SJason M. Bills prevTs = 0; 223e85d6b16SJason M. Bills } 224e85d6b16SJason M. Bills 22516428a1aSJason M. Bills // Get the entry timestamp 22616428a1aSJason M. Bills uint64_t curTs = 0; 22716428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 22816428a1aSJason M. Bills if (ret < 0) 22916428a1aSJason M. Bills { 23016428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 23116428a1aSJason M. Bills << strerror(-ret); 23216428a1aSJason M. Bills return false; 23316428a1aSJason M. Bills } 23416428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 23516428a1aSJason M. Bills if (curTs == prevTs) 23616428a1aSJason M. Bills { 23716428a1aSJason M. Bills index++; 23816428a1aSJason M. Bills } 23916428a1aSJason M. Bills else 24016428a1aSJason M. Bills { 24116428a1aSJason M. Bills // Otherwise, reset it 24216428a1aSJason M. Bills index = 0; 24316428a1aSJason M. Bills } 24416428a1aSJason M. Bills // Save the timestamp 24516428a1aSJason M. Bills prevTs = curTs; 24616428a1aSJason M. Bills 24716428a1aSJason M. Bills entryID = std::to_string(curTs); 24816428a1aSJason M. Bills if (index > 0) 24916428a1aSJason M. Bills { 25016428a1aSJason M. Bills entryID += "_" + std::to_string(index); 25116428a1aSJason M. Bills } 25216428a1aSJason M. Bills return true; 25316428a1aSJason M. Bills } 25416428a1aSJason M. Bills 255e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 256e85d6b16SJason M. Bills const bool firstEntry = true) 25795820184SJason M. Bills { 258271584abSEd Tanous static time_t prevTs = 0; 25995820184SJason M. Bills static int index = 0; 260e85d6b16SJason M. Bills if (firstEntry) 261e85d6b16SJason M. Bills { 262e85d6b16SJason M. Bills prevTs = 0; 263e85d6b16SJason M. Bills } 264e85d6b16SJason M. Bills 26595820184SJason M. Bills // Get the entry timestamp 266271584abSEd Tanous std::time_t curTs = 0; 26795820184SJason M. Bills std::tm timeStruct = {}; 26895820184SJason M. Bills std::istringstream entryStream(logEntry); 26995820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 27095820184SJason M. Bills { 27195820184SJason M. Bills curTs = std::mktime(&timeStruct); 27295820184SJason M. Bills } 27395820184SJason M. Bills // If the timestamp isn't unique, increment the index 27495820184SJason M. Bills if (curTs == prevTs) 27595820184SJason M. Bills { 27695820184SJason M. Bills index++; 27795820184SJason M. Bills } 27895820184SJason M. Bills else 27995820184SJason M. Bills { 28095820184SJason M. Bills // Otherwise, reset it 28195820184SJason M. Bills index = 0; 28295820184SJason M. Bills } 28395820184SJason M. Bills // Save the timestamp 28495820184SJason M. Bills prevTs = curTs; 28595820184SJason M. Bills 28695820184SJason M. Bills entryID = std::to_string(curTs); 28795820184SJason M. Bills if (index > 0) 28895820184SJason M. Bills { 28995820184SJason M. Bills entryID += "_" + std::to_string(index); 29095820184SJason M. Bills } 29195820184SJason M. Bills return true; 29295820184SJason M. Bills } 29395820184SJason M. Bills 2947e860f15SJohn Edward Broadbent inline static bool 2958d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2968d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2978d1b46d7Szhanghch05 uint64_t& index) 29816428a1aSJason M. Bills { 29916428a1aSJason M. Bills if (entryID.empty()) 30016428a1aSJason M. Bills { 30116428a1aSJason M. Bills return false; 30216428a1aSJason M. Bills } 30316428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 30439e77504SEd Tanous std::string_view tsStr(entryID); 30516428a1aSJason M. Bills 30681ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 30771d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 30816428a1aSJason M. Bills { 30916428a1aSJason M. Bills // Timestamp has an index 31016428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 31139e77504SEd Tanous std::string_view indexStr(entryID); 31216428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 313c0bd5e4bSEd Tanous auto [ptr, ec] = std::from_chars( 314c0bd5e4bSEd Tanous indexStr.data(), indexStr.data() + indexStr.size(), index); 315c0bd5e4bSEd Tanous if (ec != std::errc()) 31616428a1aSJason M. Bills { 3179db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 31816428a1aSJason M. Bills return false; 31916428a1aSJason M. Bills } 32016428a1aSJason M. Bills } 32116428a1aSJason M. Bills // Timestamp has no index 322c0bd5e4bSEd Tanous auto [ptr, ec] = 323c0bd5e4bSEd Tanous std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp); 324c0bd5e4bSEd Tanous if (ec != std::errc()) 32516428a1aSJason M. Bills { 3269db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 32716428a1aSJason M. Bills return false; 32816428a1aSJason M. Bills } 32916428a1aSJason M. Bills return true; 33016428a1aSJason M. Bills } 33116428a1aSJason M. Bills 33295820184SJason M. Bills static bool 33395820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 33495820184SJason M. Bills { 33595820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 33695820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 33795820184SJason M. Bills 33895820184SJason M. Bills // Loop through the directory looking for redfish log files 33995820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 34095820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 34195820184SJason M. Bills { 34295820184SJason M. Bills // If we find a redfish log file, save the path 34395820184SJason M. Bills std::string filename = dirEnt.path().filename(); 34411ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 34595820184SJason M. Bills { 34695820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 34795820184SJason M. Bills } 34895820184SJason M. Bills } 34995820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 35095820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 35195820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 35295820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 35395820184SJason M. Bills 35495820184SJason M. Bills return !redfishLogFiles.empty(); 35595820184SJason M. Bills } 35695820184SJason M. Bills 357aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3582d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 359c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 360aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 361aefe3786SClaire Weinan { 362aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 363aefe3786SClaire Weinan { 364aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 365aefe3786SClaire Weinan { 366aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 367aefe3786SClaire Weinan { 368aefe3786SClaire Weinan if (propertyMap.first == "Status") 369aefe3786SClaire Weinan { 370aefe3786SClaire Weinan const auto* status = 371aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 372aefe3786SClaire Weinan if (status == nullptr) 373aefe3786SClaire Weinan { 374aefe3786SClaire Weinan messages::internalError(asyncResp->res); 375aefe3786SClaire Weinan break; 376aefe3786SClaire Weinan } 377aefe3786SClaire Weinan dumpStatus = *status; 378aefe3786SClaire Weinan } 379aefe3786SClaire Weinan } 380aefe3786SClaire Weinan } 381aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 382aefe3786SClaire Weinan { 383aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan if (propertyMap.first == "Size") 386aefe3786SClaire Weinan { 387aefe3786SClaire Weinan const auto* sizePtr = 388aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 389aefe3786SClaire Weinan if (sizePtr == nullptr) 390aefe3786SClaire Weinan { 391aefe3786SClaire Weinan messages::internalError(asyncResp->res); 392aefe3786SClaire Weinan break; 393aefe3786SClaire Weinan } 394aefe3786SClaire Weinan size = *sizePtr; 395aefe3786SClaire Weinan break; 396aefe3786SClaire Weinan } 397aefe3786SClaire Weinan } 398aefe3786SClaire Weinan } 399aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 400aefe3786SClaire Weinan { 401aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 402aefe3786SClaire Weinan { 403aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 404aefe3786SClaire Weinan { 405aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 406aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 407aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 408aefe3786SClaire Weinan { 409aefe3786SClaire Weinan messages::internalError(asyncResp->res); 410aefe3786SClaire Weinan break; 411aefe3786SClaire Weinan } 412c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 413aefe3786SClaire Weinan break; 414aefe3786SClaire Weinan } 415aefe3786SClaire Weinan } 416aefe3786SClaire Weinan } 417aefe3786SClaire Weinan } 418aefe3786SClaire Weinan } 419aefe3786SClaire Weinan 42021ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 421fdd26906SClaire Weinan { 422fdd26906SClaire Weinan std::string entriesPath; 423fdd26906SClaire Weinan 424fdd26906SClaire Weinan if (dumpType == "BMC") 425fdd26906SClaire Weinan { 426fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 427fdd26906SClaire Weinan } 428fdd26906SClaire Weinan else if (dumpType == "FaultLog") 429fdd26906SClaire Weinan { 430fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 431fdd26906SClaire Weinan } 432fdd26906SClaire Weinan else if (dumpType == "System") 433fdd26906SClaire Weinan { 434fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 435fdd26906SClaire Weinan } 436fdd26906SClaire Weinan else 437fdd26906SClaire Weinan { 438fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 439fdd26906SClaire Weinan << dumpType; 440fdd26906SClaire Weinan } 441fdd26906SClaire Weinan 442fdd26906SClaire Weinan // Returns empty string on error 443fdd26906SClaire Weinan return entriesPath; 444fdd26906SClaire Weinan } 445fdd26906SClaire Weinan 4468d1b46d7Szhanghch05 inline void 4478d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4485cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4495cb1dd27SAsmitha Karunanithi { 450fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 451fdd26906SClaire Weinan if (entriesPath.empty()) 4525cb1dd27SAsmitha Karunanithi { 4535cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4545cb1dd27SAsmitha Karunanithi return; 4555cb1dd27SAsmitha Karunanithi } 4565cb1dd27SAsmitha Karunanithi 4575cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 458fdd26906SClaire Weinan [asyncResp, entriesPath, 459711ac7a9SEd Tanous dumpType](const boost::system::error_code ec, 460711ac7a9SEd Tanous dbus::utility::ManagedObjectType& resp) { 4615cb1dd27SAsmitha Karunanithi if (ec) 4625cb1dd27SAsmitha Karunanithi { 4635cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4645cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4655cb1dd27SAsmitha Karunanithi return; 4665cb1dd27SAsmitha Karunanithi } 4675cb1dd27SAsmitha Karunanithi 468fdd26906SClaire Weinan // Remove ending slash 469fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 470fdd26906SClaire Weinan if (!odataIdStr.empty()) 471fdd26906SClaire Weinan { 472fdd26906SClaire Weinan odataIdStr.pop_back(); 473fdd26906SClaire Weinan } 474fdd26906SClaire Weinan 475fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 476fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 477fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 478fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 479fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = 480fdd26906SClaire Weinan "Collection of " + dumpType + " Dump Entries"; 481fdd26906SClaire Weinan 4825cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4835cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 484b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 485b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 486002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 4875cb1dd27SAsmitha Karunanithi 488002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 489002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 490002d39b4SEd Tanous r.first.filename()); 491565dfb6fSClaire Weinan }); 492565dfb6fSClaire Weinan 4935cb1dd27SAsmitha Karunanithi for (auto& object : resp) 4945cb1dd27SAsmitha Karunanithi { 495b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 4965cb1dd27SAsmitha Karunanithi { 4975cb1dd27SAsmitha Karunanithi continue; 4985cb1dd27SAsmitha Karunanithi } 499c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5005cb1dd27SAsmitha Karunanithi uint64_t size = 0; 50135440d18SAsmitha Karunanithi std::string dumpStatus; 502433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5032dfd18efSEd Tanous 5042dfd18efSEd Tanous std::string entryID = object.first.filename(); 5052dfd18efSEd Tanous if (entryID.empty()) 5065cb1dd27SAsmitha Karunanithi { 5075cb1dd27SAsmitha Karunanithi continue; 5085cb1dd27SAsmitha Karunanithi } 5095cb1dd27SAsmitha Karunanithi 510c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 511aefe3786SClaire Weinan asyncResp); 5125cb1dd27SAsmitha Karunanithi 5130fda0f12SGeorge Liu if (dumpStatus != 5140fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 51535440d18SAsmitha Karunanithi !dumpStatus.empty()) 51635440d18SAsmitha Karunanithi { 51735440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 51835440d18SAsmitha Karunanithi continue; 51935440d18SAsmitha Karunanithi } 52035440d18SAsmitha Karunanithi 5219c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 522fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5235cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5245cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5255cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 526bbd80db8SClaire Weinan thisEntry["Created"] = 527bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5285cb1dd27SAsmitha Karunanithi 5295cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5305cb1dd27SAsmitha Karunanithi { 531d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 532d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 533fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 534fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5355cb1dd27SAsmitha Karunanithi } 5365cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5375cb1dd27SAsmitha Karunanithi { 538d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 539d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 540d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 541fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 542fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5435cb1dd27SAsmitha Karunanithi } 54435440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5455cb1dd27SAsmitha Karunanithi } 546002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5475cb1dd27SAsmitha Karunanithi }, 5485cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5495cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 5505cb1dd27SAsmitha Karunanithi } 5515cb1dd27SAsmitha Karunanithi 5528d1b46d7Szhanghch05 inline void 553c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5548d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5555cb1dd27SAsmitha Karunanithi { 556fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 557fdd26906SClaire Weinan if (entriesPath.empty()) 5585cb1dd27SAsmitha Karunanithi { 5595cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5605cb1dd27SAsmitha Karunanithi return; 5615cb1dd27SAsmitha Karunanithi } 5625cb1dd27SAsmitha Karunanithi 5635cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 564fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 565fdd26906SClaire Weinan entriesPath](const boost::system::error_code ec, 56602cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5675cb1dd27SAsmitha Karunanithi if (ec) 5685cb1dd27SAsmitha Karunanithi { 5695cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5705cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5715cb1dd27SAsmitha Karunanithi return; 5725cb1dd27SAsmitha Karunanithi } 5735cb1dd27SAsmitha Karunanithi 574b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 575b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 576b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 577002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 578b47452b2SAsmitha Karunanithi 5799eb808c1SEd Tanous for (const auto& objectPath : resp) 5805cb1dd27SAsmitha Karunanithi { 581b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 5825cb1dd27SAsmitha Karunanithi { 5835cb1dd27SAsmitha Karunanithi continue; 5845cb1dd27SAsmitha Karunanithi } 5855cb1dd27SAsmitha Karunanithi 5865cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 587c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5885cb1dd27SAsmitha Karunanithi uint64_t size = 0; 58935440d18SAsmitha Karunanithi std::string dumpStatus; 5905cb1dd27SAsmitha Karunanithi 591aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 592c6fecdabSClaire Weinan timestampUs, asyncResp); 5935cb1dd27SAsmitha Karunanithi 5940fda0f12SGeorge Liu if (dumpStatus != 5950fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 59635440d18SAsmitha Karunanithi !dumpStatus.empty()) 59735440d18SAsmitha Karunanithi { 59835440d18SAsmitha Karunanithi // Dump status is not Complete 59935440d18SAsmitha Karunanithi // return not found until status is changed to Completed 600d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 601d1bde9e5SKrzysztof Grobelny entryID); 60235440d18SAsmitha Karunanithi return; 60335440d18SAsmitha Karunanithi } 60435440d18SAsmitha Karunanithi 6055cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 6069c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 607fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6085cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6095cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6105cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 611bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 612bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6135cb1dd27SAsmitha Karunanithi 6145cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6155cb1dd27SAsmitha Karunanithi { 616d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 617d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 618fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 619fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6205cb1dd27SAsmitha Karunanithi } 6215cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6225cb1dd27SAsmitha Karunanithi { 623d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 624002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 625d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 626fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 627fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6285cb1dd27SAsmitha Karunanithi } 6295cb1dd27SAsmitha Karunanithi } 630e05aec50SEd Tanous if (!foundDumpEntry) 631b47452b2SAsmitha Karunanithi { 632b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 633b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 634b47452b2SAsmitha Karunanithi return; 635b47452b2SAsmitha Karunanithi } 6365cb1dd27SAsmitha Karunanithi }, 6375cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6385cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6395cb1dd27SAsmitha Karunanithi } 6405cb1dd27SAsmitha Karunanithi 6418d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6429878256fSStanley Chu const std::string& entryID, 643b47452b2SAsmitha Karunanithi const std::string& dumpType) 6445cb1dd27SAsmitha Karunanithi { 645002d39b4SEd Tanous auto respHandler = 646002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 6475cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6485cb1dd27SAsmitha Karunanithi if (ec) 6495cb1dd27SAsmitha Karunanithi { 6503de8d8baSGeorge Liu if (ec.value() == EBADR) 6513de8d8baSGeorge Liu { 6523de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6533de8d8baSGeorge Liu return; 6543de8d8baSGeorge Liu } 6555cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 656fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6575cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6585cb1dd27SAsmitha Karunanithi return; 6595cb1dd27SAsmitha Karunanithi } 6605cb1dd27SAsmitha Karunanithi }; 6615cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6625cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 663b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 664b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 665b47452b2SAsmitha Karunanithi entryID, 6665cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 6675cb1dd27SAsmitha Karunanithi } 6685cb1dd27SAsmitha Karunanithi 6698e31778eSAsmitha Karunanithi inline DumpCreationProgress 6708e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 671a43be80fSAsmitha Karunanithi { 6728e31778eSAsmitha Karunanithi if (status == 6738e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 6748e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 6758e31778eSAsmitha Karunanithi { 6768e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6778e31778eSAsmitha Karunanithi } 6788e31778eSAsmitha Karunanithi if (status == 6798e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 6808e31778eSAsmitha Karunanithi { 6818e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 6828e31778eSAsmitha Karunanithi } 6838e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 6848e31778eSAsmitha Karunanithi } 6858e31778eSAsmitha Karunanithi 6868e31778eSAsmitha Karunanithi inline DumpCreationProgress 6878e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 6888e31778eSAsmitha Karunanithi { 6898e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 6908e31778eSAsmitha Karunanithi { 6918e31778eSAsmitha Karunanithi if (key == "Status") 6928e31778eSAsmitha Karunanithi { 6938e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 6948e31778eSAsmitha Karunanithi if (value == nullptr) 6958e31778eSAsmitha Karunanithi { 6968e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 6978e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6988e31778eSAsmitha Karunanithi } 6998e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 7008e31778eSAsmitha Karunanithi } 7018e31778eSAsmitha Karunanithi } 7028e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7038e31778eSAsmitha Karunanithi } 7048e31778eSAsmitha Karunanithi 7058e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7068e31778eSAsmitha Karunanithi { 7078e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7088e31778eSAsmitha Karunanithi { 7098e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 7108e31778eSAsmitha Karunanithi } 7118e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7128e31778eSAsmitha Karunanithi { 7138e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 7148e31778eSAsmitha Karunanithi } 7158e31778eSAsmitha Karunanithi return ""; 7168e31778eSAsmitha Karunanithi } 7178e31778eSAsmitha Karunanithi 7188e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7198e31778eSAsmitha Karunanithi task::Payload&& payload, 7208e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7218e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7228e31778eSAsmitha Karunanithi { 7238e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7248e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7258e31778eSAsmitha Karunanithi 7268e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7278e31778eSAsmitha Karunanithi 7288e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7298e31778eSAsmitha Karunanithi { 7308e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 7318e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7328e31778eSAsmitha Karunanithi return; 7338e31778eSAsmitha Karunanithi } 7348e31778eSAsmitha Karunanithi 7358e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7368e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 7378e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 7388e31778eSAsmitha Karunanithi dumpId](const boost::system::error_code ec, 7398e31778eSAsmitha Karunanithi const std::string& introspectXml) { 7408e31778eSAsmitha Karunanithi if (ec) 7418e31778eSAsmitha Karunanithi { 7428e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 7438e31778eSAsmitha Karunanithi << ec.message(); 7448e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7458e31778eSAsmitha Karunanithi return; 7468e31778eSAsmitha Karunanithi } 7478e31778eSAsmitha Karunanithi 7488e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 7498e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 7508e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 7518e31778eSAsmitha Karunanithi // Else, return task completed. 7528e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 7538e31778eSAsmitha Karunanithi 7548e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 7558e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 7568e31778eSAsmitha Karunanithi if (pRoot == nullptr) 7578e31778eSAsmitha Karunanithi { 7588e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 7598e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7608e31778eSAsmitha Karunanithi return; 7618e31778eSAsmitha Karunanithi } 7628e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 7638e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 7648e31778eSAsmitha Karunanithi 7658e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 7668e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 7678e31778eSAsmitha Karunanithi { 7688e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 7698e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 7708e31778eSAsmitha Karunanithi { 7718e31778eSAsmitha Karunanithi if (thisInterfaceName == 7728e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 7738e31778eSAsmitha Karunanithi { 7748e31778eSAsmitha Karunanithi interfaceNode = 7758e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 7768e31778eSAsmitha Karunanithi continue; 7778e31778eSAsmitha Karunanithi } 7788e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 7798e31778eSAsmitha Karunanithi break; 7808e31778eSAsmitha Karunanithi } 7818e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 7828e31778eSAsmitha Karunanithi } 7838e31778eSAsmitha Karunanithi 784a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 7858e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 7865b378546SPatrick Williams boost::system::error_code err, sdbusplus::message_t& msg, 787a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 788cb13a392SEd Tanous if (err) 789cb13a392SEd Tanous { 7908e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 7918e31778eSAsmitha Karunanithi << ": Error in creating dump"; 7928e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 7936145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 7946145ed6fSAsmitha Karunanithi return task::completed; 795cb13a392SEd Tanous } 796b9d36b47SEd Tanous 7978e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 798a43be80fSAsmitha Karunanithi { 7998e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 8008e31778eSAsmitha Karunanithi std::string prop; 8018e31778eSAsmitha Karunanithi msg.read(prop, values); 8028e31778eSAsmitha Karunanithi 8038e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8048e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8058e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8068e31778eSAsmitha Karunanithi { 8078e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8088e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8098e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8108e31778eSAsmitha Karunanithi return task::completed; 8118e31778eSAsmitha Karunanithi } 8128e31778eSAsmitha Karunanithi 8138e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8148e31778eSAsmitha Karunanithi { 8158e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8168e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 8178e31778eSAsmitha Karunanithi return !task::completed; 8188e31778eSAsmitha Karunanithi } 8198e31778eSAsmitha Karunanithi } 8208e31778eSAsmitha Karunanithi 821a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 822a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 823a43be80fSAsmitha Karunanithi 824a43be80fSAsmitha Karunanithi std::string headerLoc = 8258e31778eSAsmitha Karunanithi "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId); 826002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 827a43be80fSAsmitha Karunanithi 8288e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8298e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 830a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 831b47452b2SAsmitha Karunanithi return task::completed; 832a43be80fSAsmitha Karunanithi }, 8338e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 8348e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 8358e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 836a43be80fSAsmitha Karunanithi 8378e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 8388e31778eSAsmitha Karunanithi // requested dump will be collected. 8398e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 840a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 8418e31778eSAsmitha Karunanithi task->payload.emplace(payload); 8428e31778eSAsmitha Karunanithi }, 8438e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 8448e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 845a43be80fSAsmitha Karunanithi } 846a43be80fSAsmitha Karunanithi 8478d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8488d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 849a43be80fSAsmitha Karunanithi { 850fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 851fdd26906SClaire Weinan if (dumpPath.empty()) 852a43be80fSAsmitha Karunanithi { 853a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 854a43be80fSAsmitha Karunanithi return; 855a43be80fSAsmitha Karunanithi } 856a43be80fSAsmitha Karunanithi 857a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 858a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 859a43be80fSAsmitha Karunanithi 86015ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 861a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 862a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 863a43be80fSAsmitha Karunanithi { 864a43be80fSAsmitha Karunanithi return; 865a43be80fSAsmitha Karunanithi } 866a43be80fSAsmitha Karunanithi 867a43be80fSAsmitha Karunanithi if (dumpType == "System") 868a43be80fSAsmitha Karunanithi { 869a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 870a43be80fSAsmitha Karunanithi { 8714978b63fSJason M. Bills BMCWEB_LOG_ERROR 8724978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 873a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 874a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 875a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 876a43be80fSAsmitha Karunanithi return; 877a43be80fSAsmitha Karunanithi } 8783174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 879a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 880a43be80fSAsmitha Karunanithi { 881a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 882ace85d60SEd Tanous messages::internalError(asyncResp->res); 883a43be80fSAsmitha Karunanithi return; 884a43be80fSAsmitha Karunanithi } 8855907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 886a43be80fSAsmitha Karunanithi } 887a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 888a43be80fSAsmitha Karunanithi { 889a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 890a43be80fSAsmitha Karunanithi { 8910fda0f12SGeorge Liu BMCWEB_LOG_ERROR 8920fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 893a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 894a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 895a43be80fSAsmitha Karunanithi return; 896a43be80fSAsmitha Karunanithi } 8973174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 898a43be80fSAsmitha Karunanithi { 899a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 900a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 901ace85d60SEd Tanous messages::internalError(asyncResp->res); 902a43be80fSAsmitha Karunanithi return; 903a43be80fSAsmitha Karunanithi } 9045907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 9055907571dSAsmitha Karunanithi } 9065907571dSAsmitha Karunanithi else 9075907571dSAsmitha Karunanithi { 9085907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 9095907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9105907571dSAsmitha Karunanithi return; 911a43be80fSAsmitha Karunanithi } 912a43be80fSAsmitha Karunanithi 9138e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9148e31778eSAsmitha Karunanithi createDumpParamVec; 9158e31778eSAsmitha Karunanithi 916a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9175b378546SPatrick Williams [asyncResp, payload(task::Payload(req)), dumpPath]( 9185b378546SPatrick Williams const boost::system::error_code ec, const sdbusplus::message_t& msg, 9198e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 920a43be80fSAsmitha Karunanithi if (ec) 921a43be80fSAsmitha Karunanithi { 922a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9235907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9245907571dSAsmitha Karunanithi if (dbusError == nullptr) 9255907571dSAsmitha Karunanithi { 9265907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9275907571dSAsmitha Karunanithi return; 9285907571dSAsmitha Karunanithi } 9295907571dSAsmitha Karunanithi 9305907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9315907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9325907571dSAsmitha Karunanithi if (std::string_view( 9335907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9345907571dSAsmitha Karunanithi dbusError->name) 9355907571dSAsmitha Karunanithi { 9365907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9375907571dSAsmitha Karunanithi return; 9385907571dSAsmitha Karunanithi } 9395907571dSAsmitha Karunanithi if (std::string_view( 9405907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9415907571dSAsmitha Karunanithi dbusError->name) 9425907571dSAsmitha Karunanithi { 9435907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9445907571dSAsmitha Karunanithi return; 9455907571dSAsmitha Karunanithi } 9465907571dSAsmitha Karunanithi if (std::string_view( 9475907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9485907571dSAsmitha Karunanithi dbusError->name) 9495907571dSAsmitha Karunanithi { 9505907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 9515907571dSAsmitha Karunanithi return; 9525907571dSAsmitha Karunanithi } 9535907571dSAsmitha Karunanithi // Other Dbus errors such as: 9545907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 9555907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 9565907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 9575907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 9585907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 9595907571dSAsmitha Karunanithi // back to the client. 960a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 961a43be80fSAsmitha Karunanithi return; 962a43be80fSAsmitha Karunanithi } 9638e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 9648e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 965a43be80fSAsmitha Karunanithi }, 966b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 967b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 968b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 9698e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 970a43be80fSAsmitha Karunanithi } 971a43be80fSAsmitha Karunanithi 9728d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9738d1b46d7Szhanghch05 const std::string& dumpType) 97480319af1SAsmitha Karunanithi { 975b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 976b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 977*7a1dbc48SGeorge Liu std::string interface = "xyz.openbmc_project.Dump.Entry." + dumpType; 978*7a1dbc48SGeorge Liu const std::array<const std::string_view, 1> interfaces{interface}; 9798d1b46d7Szhanghch05 980*7a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 981*7a1dbc48SGeorge Liu "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, interfaces, 982b9d36b47SEd Tanous [asyncResp, dumpType]( 983*7a1dbc48SGeorge Liu const boost::system::error_code& ec, 984b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 98580319af1SAsmitha Karunanithi if (ec) 98680319af1SAsmitha Karunanithi { 98780319af1SAsmitha Karunanithi BMCWEB_LOG_ERROR << "resp_handler got error " << ec; 98880319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 98980319af1SAsmitha Karunanithi return; 99080319af1SAsmitha Karunanithi } 99180319af1SAsmitha Karunanithi 99280319af1SAsmitha Karunanithi for (const std::string& path : subTreePaths) 99380319af1SAsmitha Karunanithi { 9942dfd18efSEd Tanous sdbusplus::message::object_path objPath(path); 9952dfd18efSEd Tanous std::string logID = objPath.filename(); 9962dfd18efSEd Tanous if (logID.empty()) 99780319af1SAsmitha Karunanithi { 9982dfd18efSEd Tanous continue; 99980319af1SAsmitha Karunanithi } 10002dfd18efSEd Tanous deleteDumpEntry(asyncResp, logID, dumpType); 100180319af1SAsmitha Karunanithi } 1002*7a1dbc48SGeorge Liu }); 100380319af1SAsmitha Karunanithi } 100480319af1SAsmitha Karunanithi 1005b9d36b47SEd Tanous inline static void 1006b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1007b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1008b9d36b47SEd Tanous std::string& logfile) 1009043a0536SJohnathan Mantey { 1010d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1011d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1012d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1013d1bde9e5SKrzysztof Grobelny 1014d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1015d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1016d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1017d1bde9e5SKrzysztof Grobelny 1018d1bde9e5SKrzysztof Grobelny if (!success) 1019043a0536SJohnathan Mantey { 1020d1bde9e5SKrzysztof Grobelny return; 1021043a0536SJohnathan Mantey } 1022d1bde9e5SKrzysztof Grobelny 1023d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1024043a0536SJohnathan Mantey { 1025d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1026d1bde9e5SKrzysztof Grobelny } 1027d1bde9e5SKrzysztof Grobelny 1028d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1029043a0536SJohnathan Mantey { 1030d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1031043a0536SJohnathan Mantey } 1032d1bde9e5SKrzysztof Grobelny 1033d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1034043a0536SJohnathan Mantey { 1035d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1036043a0536SJohnathan Mantey } 1037043a0536SJohnathan Mantey } 1038043a0536SJohnathan Mantey 10397e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10401da66f75SEd Tanous { 1041c4bf6374SJason M. Bills /** 1042c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1043c4bf6374SJason M. Bills */ 104422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1045ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1046002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1047002d39b4SEd Tanous [&app](const crow::Request& req, 104822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 104922d268cbSEd Tanous const std::string& systemName) { 10503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1051c4bf6374SJason M. Bills { 105245ca1b86SEd Tanous return; 105345ca1b86SEd Tanous } 105422d268cbSEd Tanous if (systemName != "system") 105522d268cbSEd Tanous { 105622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 105722d268cbSEd Tanous systemName); 105822d268cbSEd Tanous return; 105922d268cbSEd Tanous } 106022d268cbSEd Tanous 10617e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10627e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1063c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1064c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1065c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1066029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 106745ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1068c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1069c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1070002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1071c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 10721476687dSEd Tanous nlohmann::json::object_t eventLog; 10731476687dSEd Tanous eventLog["@odata.id"] = 10741476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 10751476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 10765cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 10771476687dSEd Tanous nlohmann::json::object_t dumpLog; 1078002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 10791476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 1080c9bb6861Sraviteja-b #endif 1081c9bb6861Sraviteja-b 1082d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 10831476687dSEd Tanous nlohmann::json::object_t crashdump; 10841476687dSEd Tanous crashdump["@odata.id"] = 10851476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 10861476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 1087d53dd41fSJason M. Bills #endif 1088b7028ebfSSpencer Ku 1089b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 10901476687dSEd Tanous nlohmann::json::object_t hostlogger; 10911476687dSEd Tanous hostlogger["@odata.id"] = 10921476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 10931476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 1094b7028ebfSSpencer Ku #endif 1095c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1096c4bf6374SJason M. Bills logServiceArray.size(); 1097a3316fc6SZhikuiRen 1098*7a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1099*7a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 1100*7a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 1101*7a1dbc48SGeorge Liu "/", 0, interfaces, 1102*7a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1103b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1104b9d36b47SEd Tanous subtreePath) { 1105a3316fc6SZhikuiRen if (ec) 1106a3316fc6SZhikuiRen { 1107a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << ec; 1108a3316fc6SZhikuiRen return; 1109a3316fc6SZhikuiRen } 1110a3316fc6SZhikuiRen 111155f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1112a3316fc6SZhikuiRen { 1113a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1114a3316fc6SZhikuiRen { 111523a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1116a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1117613dabeaSEd Tanous nlohmann::json::object_t member; 1118613dabeaSEd Tanous member["@odata.id"] = 1119613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1120613dabeaSEd Tanous 1121613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 1122613dabeaSEd Tanous 112345ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 112423a21a1cSEd Tanous logServiceArrayLocal.size(); 1125a3316fc6SZhikuiRen return; 1126a3316fc6SZhikuiRen } 1127a3316fc6SZhikuiRen } 1128*7a1dbc48SGeorge Liu }); 11297e860f15SJohn Edward Broadbent }); 1130c4bf6374SJason M. Bills } 1131c4bf6374SJason M. Bills 11327e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1133c4bf6374SJason M. Bills { 113422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1135ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1136002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1137002d39b4SEd Tanous [&app](const crow::Request& req, 113822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 113922d268cbSEd Tanous const std::string& systemName) { 11403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114145ca1b86SEd Tanous { 114245ca1b86SEd Tanous return; 114345ca1b86SEd Tanous } 114422d268cbSEd Tanous if (systemName != "system") 114522d268cbSEd Tanous { 114622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 114722d268cbSEd Tanous systemName); 114822d268cbSEd Tanous return; 114922d268cbSEd Tanous } 1150c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1151029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1152c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1153c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1154c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1155002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1156c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1157c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11587c8c4058STejas Patil 11597c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11602b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11617c8c4058STejas Patil 11627c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 11637c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 11647c8c4058STejas Patil redfishDateTimeOffset.second; 11657c8c4058STejas Patil 11661476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 11671476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1168e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1169e7d6c8b2SGunnar Mills 11700fda0f12SGeorge Liu {"target", 11710fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 11727e860f15SJohn Edward Broadbent }); 1173489640c6SJason M. Bills } 1174489640c6SJason M. Bills 11757e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1176489640c6SJason M. Bills { 11774978b63fSJason M. Bills BMCWEB_ROUTE( 11784978b63fSJason M. Bills app, 117922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1180432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 11817e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 118245ca1b86SEd Tanous [&app](const crow::Request& req, 118322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 118422d268cbSEd Tanous const std::string& systemName) { 11853ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 118645ca1b86SEd Tanous { 118745ca1b86SEd Tanous return; 118845ca1b86SEd Tanous } 118922d268cbSEd Tanous if (systemName != "system") 119022d268cbSEd Tanous { 119122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 119222d268cbSEd Tanous systemName); 119322d268cbSEd Tanous return; 119422d268cbSEd Tanous } 1195489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1196489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1197489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1198489640c6SJason M. Bills { 1199489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1200489640c6SJason M. Bills { 1201489640c6SJason M. Bills std::error_code ec; 1202489640c6SJason M. Bills std::filesystem::remove(file, ec); 1203489640c6SJason M. Bills } 1204489640c6SJason M. Bills } 1205489640c6SJason M. Bills 1206489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1207489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 1208489640c6SJason M. Bills [asyncResp](const boost::system::error_code ec) { 1209489640c6SJason M. Bills if (ec) 1210489640c6SJason M. Bills { 1211002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1212489640c6SJason M. Bills messages::internalError(asyncResp->res); 1213489640c6SJason M. Bills return; 1214489640c6SJason M. Bills } 1215489640c6SJason M. Bills 1216489640c6SJason M. Bills messages::success(asyncResp->res); 1217489640c6SJason M. Bills }, 1218489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1219002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1220002d39b4SEd Tanous "replace"); 12217e860f15SJohn Edward Broadbent }); 1222c4bf6374SJason M. Bills } 1223c4bf6374SJason M. Bills 1224ac992cdeSJason M. Bills enum class LogParseError 1225ac992cdeSJason M. Bills { 1226ac992cdeSJason M. Bills success, 1227ac992cdeSJason M. Bills parseFailed, 1228ac992cdeSJason M. Bills messageIdNotInRegistry, 1229ac992cdeSJason M. Bills }; 1230ac992cdeSJason M. Bills 1231ac992cdeSJason M. Bills static LogParseError 1232ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1233b5a76932SEd Tanous const std::string& logEntry, 1234de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1235c4bf6374SJason M. Bills { 123695820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1237cd225da8SJason M. Bills // First get the Timestamp 1238f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1239cd225da8SJason M. Bills if (space == std::string::npos) 124095820184SJason M. Bills { 1241ac992cdeSJason M. Bills return LogParseError::parseFailed; 124295820184SJason M. Bills } 1243cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1244cd225da8SJason M. Bills // Then get the log contents 1245f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1246cd225da8SJason M. Bills if (entryStart == std::string::npos) 1247cd225da8SJason M. Bills { 1248ac992cdeSJason M. Bills return LogParseError::parseFailed; 1249cd225da8SJason M. Bills } 1250cd225da8SJason M. Bills std::string_view entry(logEntry); 1251cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1252cd225da8SJason M. Bills // Use split to separate the entry into its fields 1253cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 1254cd225da8SJason M. Bills boost::split(logEntryFields, entry, boost::is_any_of(","), 1255cd225da8SJason M. Bills boost::token_compress_on); 1256cd225da8SJason M. Bills // We need at least a MessageId to be valid 125726f6976fSEd Tanous if (logEntryFields.empty()) 1258cd225da8SJason M. Bills { 1259ac992cdeSJason M. Bills return LogParseError::parseFailed; 1260cd225da8SJason M. Bills } 1261cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 126295820184SJason M. Bills 12634851d45dSJason M. Bills // Get the Message from the MessageRegistry 1264fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1265c4bf6374SJason M. Bills 126654417b02SSui Chen if (message == nullptr) 1267c4bf6374SJason M. Bills { 126854417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1269ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1270c4bf6374SJason M. Bills } 1271c4bf6374SJason M. Bills 127254417b02SSui Chen std::string msg = message->message; 127354417b02SSui Chen 127415a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 127526702d01SEd Tanous std::span<std::string> messageArgs; 127615a86ff6SJason M. Bills if (logEntryFields.size() > 1) 127715a86ff6SJason M. Bills { 127815a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 127915a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 128015a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 128115a86ff6SJason M. Bills if (!messageArgsStart.empty()) 128215a86ff6SJason M. Bills { 128315a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 128415a86ff6SJason M. Bills } 128515a86ff6SJason M. Bills 128623a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1287c4bf6374SJason M. Bills 12884851d45dSJason M. Bills // Fill the MessageArgs into the Message 128995820184SJason M. Bills int i = 0; 129095820184SJason M. Bills for (const std::string& messageArg : messageArgs) 12914851d45dSJason M. Bills { 129295820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 12934851d45dSJason M. Bills size_t argPos = msg.find(argStr); 12944851d45dSJason M. Bills if (argPos != std::string::npos) 12954851d45dSJason M. Bills { 129695820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 12974851d45dSJason M. Bills } 12984851d45dSJason M. Bills } 129915a86ff6SJason M. Bills } 13004851d45dSJason M. Bills 130195820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 130295820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 130395820184SJason M. Bills // between the '.' and the '+', so just remove them. 1304f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1305f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 130695820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1307c4bf6374SJason M. Bills { 130895820184SJason M. Bills timestamp.erase(dot, plus - dot); 1309c4bf6374SJason M. Bills } 1310c4bf6374SJason M. Bills 1311c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13129c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 131384afc48bSJason M. Bills logEntryJson["@odata.id"] = 131484afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID; 131584afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 131684afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 131784afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 131884afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 131984afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 132084afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 132184afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 132284afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1323ac992cdeSJason M. Bills return LogParseError::success; 1324c4bf6374SJason M. Bills } 1325c4bf6374SJason M. Bills 13267e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1327c4bf6374SJason M. Bills { 132822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13298b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1330002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1331002d39b4SEd Tanous [&app](const crow::Request& req, 133222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 133322d268cbSEd Tanous const std::string& systemName) { 1334c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1335c937d2bfSEd Tanous .canDelegateTop = true, 1336c937d2bfSEd Tanous .canDelegateSkip = true, 1337c937d2bfSEd Tanous }; 1338c937d2bfSEd Tanous query_param::Query delegatedQuery; 1339c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13403ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1341c4bf6374SJason M. Bills { 1342c4bf6374SJason M. Bills return; 1343c4bf6374SJason M. Bills } 134422d268cbSEd Tanous if (systemName != "system") 134522d268cbSEd Tanous { 134622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 134722d268cbSEd Tanous systemName); 134822d268cbSEd Tanous return; 134922d268cbSEd Tanous } 135022d268cbSEd Tanous 13515143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13523648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13533648c8beSEd Tanous 13547e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13557e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1356c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1357c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1358c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1359029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1360c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1361c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1362c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1363cb92c03bSAndrew Geissler 13644978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1365c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13667e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13677e860f15SJohn Edward Broadbent // entry 136895820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 136995820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1370b01bf299SEd Tanous uint64_t entryCount = 0; 1371cd225da8SJason M. Bills std::string logEntry; 137295820184SJason M. Bills 13737e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13747e860f15SJohn Edward Broadbent // backwards 1375002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1376002d39b4SEd Tanous it++) 1377c4bf6374SJason M. Bills { 1378cd225da8SJason M. Bills std::ifstream logStream(*it); 137995820184SJason M. Bills if (!logStream.is_open()) 1380c4bf6374SJason M. Bills { 1381c4bf6374SJason M. Bills continue; 1382c4bf6374SJason M. Bills } 1383c4bf6374SJason M. Bills 1384e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1385e85d6b16SJason M. Bills bool firstEntry = true; 138695820184SJason M. Bills while (std::getline(logStream, logEntry)) 138795820184SJason M. Bills { 1388c4bf6374SJason M. Bills std::string idStr; 1389e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1390c4bf6374SJason M. Bills { 1391c4bf6374SJason M. Bills continue; 1392c4bf6374SJason M. Bills } 1393e85d6b16SJason M. Bills firstEntry = false; 1394e85d6b16SJason M. Bills 1395de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1396ac992cdeSJason M. Bills LogParseError status = 1397ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1398ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1399ac992cdeSJason M. Bills { 1400ac992cdeSJason M. Bills continue; 1401ac992cdeSJason M. Bills } 1402ac992cdeSJason M. Bills if (status != LogParseError::success) 1403c4bf6374SJason M. Bills { 1404c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1405c4bf6374SJason M. Bills return; 1406c4bf6374SJason M. Bills } 1407de703c5dSJason M. Bills 1408de703c5dSJason M. Bills entryCount++; 1409de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1410de703c5dSJason M. Bills // start) and top (number of entries to display) 14113648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1412de703c5dSJason M. Bills { 1413de703c5dSJason M. Bills continue; 1414de703c5dSJason M. Bills } 1415de703c5dSJason M. Bills 1416de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1417c4bf6374SJason M. Bills } 141895820184SJason M. Bills } 1419c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14203648c8beSEd Tanous if (skip + top < entryCount) 1421c4bf6374SJason M. Bills { 1422c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14234978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14243648c8beSEd Tanous std::to_string(skip + top); 1425c4bf6374SJason M. Bills } 14267e860f15SJohn Edward Broadbent }); 1427897967deSJason M. Bills } 1428897967deSJason M. Bills 14297e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1430897967deSJason M. Bills { 14317e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 143222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1433ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 143545ca1b86SEd Tanous [&app](const crow::Request& req, 14367e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 143722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 143945ca1b86SEd Tanous { 144045ca1b86SEd Tanous return; 144145ca1b86SEd Tanous } 144222d268cbSEd Tanous 144322d268cbSEd Tanous if (systemName != "system") 144422d268cbSEd Tanous { 144522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 144622d268cbSEd Tanous systemName); 144722d268cbSEd Tanous return; 144822d268cbSEd Tanous } 144922d268cbSEd Tanous 14507e860f15SJohn Edward Broadbent const std::string& targetID = param; 14518d1b46d7Szhanghch05 14527e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14537e860f15SJohn Edward Broadbent // entry to find the target entry 1454897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1455897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1456897967deSJason M. Bills std::string logEntry; 1457897967deSJason M. Bills 14587e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14597e860f15SJohn Edward Broadbent // backwards 1460002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1461002d39b4SEd Tanous it++) 1462897967deSJason M. Bills { 1463897967deSJason M. Bills std::ifstream logStream(*it); 1464897967deSJason M. Bills if (!logStream.is_open()) 1465897967deSJason M. Bills { 1466897967deSJason M. Bills continue; 1467897967deSJason M. Bills } 1468897967deSJason M. Bills 1469897967deSJason M. Bills // Reset the unique ID on the first entry 1470897967deSJason M. Bills bool firstEntry = true; 1471897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1472897967deSJason M. Bills { 1473897967deSJason M. Bills std::string idStr; 1474897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1475897967deSJason M. Bills { 1476897967deSJason M. Bills continue; 1477897967deSJason M. Bills } 1478897967deSJason M. Bills firstEntry = false; 1479897967deSJason M. Bills 1480897967deSJason M. Bills if (idStr == targetID) 1481897967deSJason M. Bills { 1482de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1483ac992cdeSJason M. Bills LogParseError status = 1484ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1485ac992cdeSJason M. Bills if (status != LogParseError::success) 1486897967deSJason M. Bills { 1487897967deSJason M. Bills messages::internalError(asyncResp->res); 1488897967deSJason M. Bills return; 1489897967deSJason M. Bills } 1490d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1491897967deSJason M. Bills return; 1492897967deSJason M. Bills } 1493897967deSJason M. Bills } 1494897967deSJason M. Bills } 1495897967deSJason M. Bills // Requested ID was not found 14969db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 14977e860f15SJohn Edward Broadbent }); 149808a4e4b5SAnthony Wilson } 149908a4e4b5SAnthony Wilson 15007e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 150108a4e4b5SAnthony Wilson { 150222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1503ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1504002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1505002d39b4SEd Tanous [&app](const crow::Request& req, 150622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 150722d268cbSEd Tanous const std::string& systemName) { 15083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 150945ca1b86SEd Tanous { 151045ca1b86SEd Tanous return; 151145ca1b86SEd Tanous } 151222d268cbSEd Tanous if (systemName != "system") 151322d268cbSEd Tanous { 151422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 151522d268cbSEd Tanous systemName); 151622d268cbSEd Tanous return; 151722d268cbSEd Tanous } 151822d268cbSEd Tanous 15197e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15207e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 152108a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 152208a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 152308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 152408a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 152508a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 152608a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 152708a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 152808a4e4b5SAnthony Wilson 1529cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1530cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1531cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 1532cb92c03bSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1533914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1534cb92c03bSAndrew Geissler if (ec) 1535cb92c03bSAndrew Geissler { 1536cb92c03bSAndrew Geissler // TODO Handle for specific error code 1537cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1538002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1539cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1540cb92c03bSAndrew Geissler return; 1541cb92c03bSAndrew Geissler } 1542002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1543cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15449eb808c1SEd Tanous for (const auto& objectPath : resp) 1545cb92c03bSAndrew Geissler { 1546914e2d5dSEd Tanous const uint32_t* id = nullptr; 1547c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1548c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1549914e2d5dSEd Tanous const std::string* severity = nullptr; 1550914e2d5dSEd Tanous const std::string* message = nullptr; 1551914e2d5dSEd Tanous const std::string* filePath = nullptr; 15529c11a172SVijay Lobo const std::string* resolution = nullptr; 155375710de2SXiaochao Ma bool resolved = false; 15549017faf2SAbhishek Patel const std::string* notify = nullptr; 15559017faf2SAbhishek Patel 15569eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1557f86bb901SAdriana Kobylak { 1558f86bb901SAdriana Kobylak if (interfaceMap.first == 1559f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1560f86bb901SAdriana Kobylak { 1561002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1562cb92c03bSAndrew Geissler { 1563cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1564cb92c03bSAndrew Geissler { 1565002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1566cb92c03bSAndrew Geissler } 1567cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1568cb92c03bSAndrew Geissler { 1569002d39b4SEd Tanous timestamp = 1570002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15717e860f15SJohn Edward Broadbent } 1572002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 15737e860f15SJohn Edward Broadbent { 1574002d39b4SEd Tanous updateTimestamp = 1575002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15767e860f15SJohn Edward Broadbent } 15777e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 15787e860f15SJohn Edward Broadbent { 15797e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 15807e860f15SJohn Edward Broadbent &propertyMap.second); 15817e860f15SJohn Edward Broadbent } 15829c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 15839c11a172SVijay Lobo { 15849c11a172SVijay Lobo resolution = std::get_if<std::string>( 15859c11a172SVijay Lobo &propertyMap.second); 15869c11a172SVijay Lobo } 15877e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 15887e860f15SJohn Edward Broadbent { 15897e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 15907e860f15SJohn Edward Broadbent &propertyMap.second); 15917e860f15SJohn Edward Broadbent } 15927e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 15937e860f15SJohn Edward Broadbent { 1594914e2d5dSEd Tanous const bool* resolveptr = 1595002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 15967e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 15977e860f15SJohn Edward Broadbent { 1598002d39b4SEd Tanous messages::internalError(asyncResp->res); 15997e860f15SJohn Edward Broadbent return; 16007e860f15SJohn Edward Broadbent } 16017e860f15SJohn Edward Broadbent resolved = *resolveptr; 16027e860f15SJohn Edward Broadbent } 16039017faf2SAbhishek Patel else if (propertyMap.first == 16049017faf2SAbhishek Patel "ServiceProviderNotify") 16059017faf2SAbhishek Patel { 16069017faf2SAbhishek Patel notify = std::get_if<std::string>( 16079017faf2SAbhishek Patel &propertyMap.second); 16089017faf2SAbhishek Patel if (notify == nullptr) 16099017faf2SAbhishek Patel { 16109017faf2SAbhishek Patel messages::internalError(asyncResp->res); 16119017faf2SAbhishek Patel return; 16129017faf2SAbhishek Patel } 16139017faf2SAbhishek Patel } 16147e860f15SJohn Edward Broadbent } 16157e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16167e860f15SJohn Edward Broadbent severity == nullptr) 16177e860f15SJohn Edward Broadbent { 16187e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16197e860f15SJohn Edward Broadbent return; 16207e860f15SJohn Edward Broadbent } 16217e860f15SJohn Edward Broadbent } 16227e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16237e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16247e860f15SJohn Edward Broadbent { 1625002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16267e860f15SJohn Edward Broadbent { 16277e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16287e860f15SJohn Edward Broadbent { 16297e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16307e860f15SJohn Edward Broadbent &propertyMap.second); 16317e860f15SJohn Edward Broadbent } 16327e860f15SJohn Edward Broadbent } 16337e860f15SJohn Edward Broadbent } 16347e860f15SJohn Edward Broadbent } 16357e860f15SJohn Edward Broadbent // Object path without the 16367e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16377e860f15SJohn Edward Broadbent // and continue. 16387e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1639c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1640c419c759SEd Tanous updateTimestamp == nullptr) 16417e860f15SJohn Edward Broadbent { 16427e860f15SJohn Edward Broadbent continue; 16437e860f15SJohn Edward Broadbent } 16447e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16457e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16469c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 16477e860f15SJohn Edward Broadbent thisEntry["@odata.id"] = 16480fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16497e860f15SJohn Edward Broadbent std::to_string(*id); 16507e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16517e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16527e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16537e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16549c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16559c11a172SVijay Lobo { 16569c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16579c11a172SVijay Lobo } 16589017faf2SAbhishek Patel std::optional<bool> notifyAction = 16599017faf2SAbhishek Patel getProviderNotifyAction(*notify); 16609017faf2SAbhishek Patel if (notifyAction) 16619017faf2SAbhishek Patel { 16629017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 16639017faf2SAbhishek Patel } 16647e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16657e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16667e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16677e860f15SJohn Edward Broadbent thisEntry["Created"] = 16682b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 16697e860f15SJohn Edward Broadbent thisEntry["Modified"] = 16702b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 16717e860f15SJohn Edward Broadbent if (filePath != nullptr) 16727e860f15SJohn Edward Broadbent { 16737e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 16740fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16757e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 16767e860f15SJohn Edward Broadbent } 16777e860f15SJohn Edward Broadbent } 1678002d39b4SEd Tanous std::sort( 1679002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1680002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 16817e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 16827e860f15SJohn Edward Broadbent }); 16837e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 16847e860f15SJohn Edward Broadbent entriesArray.size(); 16857e860f15SJohn Edward Broadbent }, 16867e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 16877e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 16887e860f15SJohn Edward Broadbent }); 16897e860f15SJohn Edward Broadbent } 16907e860f15SJohn Edward Broadbent 16917e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 16927e860f15SJohn Edward Broadbent { 16937e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 169422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1695ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1696002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1697002d39b4SEd Tanous [&app](const crow::Request& req, 16987e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 169922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17003ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17017e860f15SJohn Edward Broadbent { 170245ca1b86SEd Tanous return; 170345ca1b86SEd Tanous } 170422d268cbSEd Tanous if (systemName != "system") 170522d268cbSEd Tanous { 170622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 170722d268cbSEd Tanous systemName); 170822d268cbSEd Tanous return; 170922d268cbSEd Tanous } 171022d268cbSEd Tanous 17117e860f15SJohn Edward Broadbent std::string entryID = param; 17127e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17137e860f15SJohn Edward Broadbent 17147e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17157e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1716d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1717d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1718d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 1719002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1720b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17217e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17227e860f15SJohn Edward Broadbent { 1723d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1724d1bde9e5SKrzysztof Grobelny entryID); 17257e860f15SJohn Edward Broadbent return; 17267e860f15SJohn Edward Broadbent } 17277e860f15SJohn Edward Broadbent if (ec) 17287e860f15SJohn Edward Broadbent { 17290fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1730002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17317e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17327e860f15SJohn Edward Broadbent return; 17337e860f15SJohn Edward Broadbent } 1734914e2d5dSEd Tanous const uint32_t* id = nullptr; 1735c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1736c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1737914e2d5dSEd Tanous const std::string* severity = nullptr; 1738914e2d5dSEd Tanous const std::string* message = nullptr; 1739914e2d5dSEd Tanous const std::string* filePath = nullptr; 17409c11a172SVijay Lobo const std::string* resolution = nullptr; 17417e860f15SJohn Edward Broadbent bool resolved = false; 17429017faf2SAbhishek Patel const std::string* notify = nullptr; 17437e860f15SJohn Edward Broadbent 1744d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1745d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1746d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17479c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 17489017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 17499017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1750d1bde9e5SKrzysztof Grobelny 1751d1bde9e5SKrzysztof Grobelny if (!success) 175275710de2SXiaochao Ma { 175375710de2SXiaochao Ma messages::internalError(asyncResp->res); 175475710de2SXiaochao Ma return; 175575710de2SXiaochao Ma } 1756d1bde9e5SKrzysztof Grobelny 1757002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 17589017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 17599017faf2SAbhishek Patel notify == nullptr) 1760f86bb901SAdriana Kobylak { 1761ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1762271584abSEd Tanous return; 1763271584abSEd Tanous } 17649017faf2SAbhishek Patel 1765f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17669c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1767f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 17680fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1769f86bb901SAdriana Kobylak std::to_string(*id); 177045ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1771f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1772f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1773f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 17749017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 17759017faf2SAbhishek Patel if (notifyAction) 17769017faf2SAbhishek Patel { 17779017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 17789017faf2SAbhishek Patel *notifyAction; 17799017faf2SAbhishek Patel } 17809c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17819c11a172SVijay Lobo { 17829c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 17839c11a172SVijay Lobo } 1784f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1785f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1786f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1787f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 17882b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1789f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 17902b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1791f86bb901SAdriana Kobylak if (filePath != nullptr) 1792f86bb901SAdriana Kobylak { 1793f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1794e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1795e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1796f86bb901SAdriana Kobylak } 1797d1bde9e5SKrzysztof Grobelny }); 17987e860f15SJohn Edward Broadbent }); 1799336e96c6SChicago Duan 18007e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 180122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1802ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18037e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 180445ca1b86SEd Tanous [&app](const crow::Request& req, 18057e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 180622d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 18073ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 180845ca1b86SEd Tanous { 180945ca1b86SEd Tanous return; 181045ca1b86SEd Tanous } 181122d268cbSEd Tanous if (systemName != "system") 181222d268cbSEd Tanous { 181322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 181422d268cbSEd Tanous systemName); 181522d268cbSEd Tanous return; 181622d268cbSEd Tanous } 181775710de2SXiaochao Ma std::optional<bool> resolved; 181875710de2SXiaochao Ma 181915ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 18207e860f15SJohn Edward Broadbent resolved)) 182175710de2SXiaochao Ma { 182275710de2SXiaochao Ma return; 182375710de2SXiaochao Ma } 182475710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 182575710de2SXiaochao Ma 182675710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 18274f48d5f6SEd Tanous [asyncResp, entryId](const boost::system::error_code ec) { 182875710de2SXiaochao Ma if (ec) 182975710de2SXiaochao Ma { 183075710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 183175710de2SXiaochao Ma messages::internalError(asyncResp->res); 183275710de2SXiaochao Ma return; 183375710de2SXiaochao Ma } 183475710de2SXiaochao Ma }, 183575710de2SXiaochao Ma "xyz.openbmc_project.Logging", 183675710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 183775710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 183875710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1839168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18407e860f15SJohn Edward Broadbent }); 184175710de2SXiaochao Ma 18427e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 184322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1844ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1845ed398213SEd Tanous 1846002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1847002d39b4SEd Tanous [&app](const crow::Request& req, 1848002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 184922d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1851336e96c6SChicago Duan { 185245ca1b86SEd Tanous return; 185345ca1b86SEd Tanous } 185422d268cbSEd Tanous if (systemName != "system") 185522d268cbSEd Tanous { 185622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 185722d268cbSEd Tanous systemName); 185822d268cbSEd Tanous return; 185922d268cbSEd Tanous } 1860336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1861336e96c6SChicago Duan 18627e860f15SJohn Edward Broadbent std::string entryID = param; 1863336e96c6SChicago Duan 1864336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1865336e96c6SChicago Duan 1866336e96c6SChicago Duan // Process response from Logging service. 1867002d39b4SEd Tanous auto respHandler = 1868002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 1869002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1870336e96c6SChicago Duan if (ec) 1871336e96c6SChicago Duan { 18723de8d8baSGeorge Liu if (ec.value() == EBADR) 18733de8d8baSGeorge Liu { 187445ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 187545ca1b86SEd Tanous entryID); 18763de8d8baSGeorge Liu return; 18773de8d8baSGeorge Liu } 1878336e96c6SChicago Duan // TODO Handle for specific error code 18790fda0f12SGeorge Liu BMCWEB_LOG_ERROR 18800fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1881336e96c6SChicago Duan << ec; 1882336e96c6SChicago Duan asyncResp->res.result( 1883336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1884336e96c6SChicago Duan return; 1885336e96c6SChicago Duan } 1886336e96c6SChicago Duan 1887336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1888336e96c6SChicago Duan }; 1889336e96c6SChicago Duan 1890336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1891336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1892336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1893336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1894336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 18957e860f15SJohn Edward Broadbent }); 1896400fd1fbSAdriana Kobylak } 1897400fd1fbSAdriana Kobylak 18987e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1899400fd1fbSAdriana Kobylak { 19000fda0f12SGeorge Liu BMCWEB_ROUTE( 19010fda0f12SGeorge Liu app, 190222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1903ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 19047e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 190545ca1b86SEd Tanous [&app](const crow::Request& req, 19067e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 190722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19097e860f15SJohn Edward Broadbent { 191045ca1b86SEd Tanous return; 191145ca1b86SEd Tanous } 191299351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 191399351cd8SEd Tanous req.getHeaderValue("Accept"), 19144a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1915400fd1fbSAdriana Kobylak { 1916002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1917400fd1fbSAdriana Kobylak return; 1918400fd1fbSAdriana Kobylak } 191922d268cbSEd Tanous if (systemName != "system") 192022d268cbSEd Tanous { 192122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 192222d268cbSEd Tanous systemName); 192322d268cbSEd Tanous return; 192422d268cbSEd Tanous } 1925400fd1fbSAdriana Kobylak 19267e860f15SJohn Edward Broadbent std::string entryID = param; 1927400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1928400fd1fbSAdriana Kobylak 1929400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 1930002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1931400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1932400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1933400fd1fbSAdriana Kobylak { 1934002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1935002d39b4SEd Tanous entryID); 1936400fd1fbSAdriana Kobylak return; 1937400fd1fbSAdriana Kobylak } 1938400fd1fbSAdriana Kobylak if (ec) 1939400fd1fbSAdriana Kobylak { 1940400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1941400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1942400fd1fbSAdriana Kobylak return; 1943400fd1fbSAdriana Kobylak } 1944400fd1fbSAdriana Kobylak 1945400fd1fbSAdriana Kobylak int fd = -1; 1946400fd1fbSAdriana Kobylak fd = dup(unixfd); 1947400fd1fbSAdriana Kobylak if (fd == -1) 1948400fd1fbSAdriana Kobylak { 1949400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1950400fd1fbSAdriana Kobylak return; 1951400fd1fbSAdriana Kobylak } 1952400fd1fbSAdriana Kobylak 1953400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1954400fd1fbSAdriana Kobylak if (size == -1) 1955400fd1fbSAdriana Kobylak { 1956400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1957400fd1fbSAdriana Kobylak return; 1958400fd1fbSAdriana Kobylak } 1959400fd1fbSAdriana Kobylak 1960400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1961400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1962400fd1fbSAdriana Kobylak if (size > maxFileSize) 1963400fd1fbSAdriana Kobylak { 1964002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1965400fd1fbSAdriana Kobylak << maxFileSize; 1966400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1967400fd1fbSAdriana Kobylak return; 1968400fd1fbSAdriana Kobylak } 1969400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1970400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1971400fd1fbSAdriana Kobylak if (rc == -1) 1972400fd1fbSAdriana Kobylak { 1973400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1974400fd1fbSAdriana Kobylak return; 1975400fd1fbSAdriana Kobylak } 1976400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1977400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1978400fd1fbSAdriana Kobylak { 1979400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1980400fd1fbSAdriana Kobylak return; 1981400fd1fbSAdriana Kobylak } 1982400fd1fbSAdriana Kobylak close(fd); 1983400fd1fbSAdriana Kobylak 1984400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 1985002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 1986400fd1fbSAdriana Kobylak 1987d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 1988400fd1fbSAdriana Kobylak "application/octet-stream"); 1989d9f6c621SEd Tanous asyncResp->res.addHeader( 1990d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 1991400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 1992400fd1fbSAdriana Kobylak }, 1993400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 1994400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 1995400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 19967e860f15SJohn Edward Broadbent }); 19971da66f75SEd Tanous } 19981da66f75SEd Tanous 1999b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2000b7028ebfSSpencer Ku 2001b7028ebfSSpencer Ku inline bool 2002b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2003b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2004b7028ebfSSpencer Ku { 2005b7028ebfSSpencer Ku std::error_code ec; 2006b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2007b7028ebfSSpencer Ku if (ec) 2008b7028ebfSSpencer Ku { 2009b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 2010b7028ebfSSpencer Ku return false; 2011b7028ebfSSpencer Ku } 2012b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2013b7028ebfSSpencer Ku { 2014b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2015b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2016b7028ebfSSpencer Ku // path 201711ba3979SEd Tanous if (filename.starts_with("log")) 2018b7028ebfSSpencer Ku { 2019b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2020b7028ebfSSpencer Ku } 2021b7028ebfSSpencer Ku } 2022b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2023b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2024b7028ebfSSpencer Ku // descending order. 2025b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2026b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2027b7028ebfSSpencer Ku 2028b7028ebfSSpencer Ku return true; 2029b7028ebfSSpencer Ku } 2030b7028ebfSSpencer Ku 203102cad96eSEd Tanous inline bool getHostLoggerEntries( 203202cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 203302cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2034b7028ebfSSpencer Ku { 2035b7028ebfSSpencer Ku GzFileReader logFile; 2036b7028ebfSSpencer Ku 2037b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2038b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2039b7028ebfSSpencer Ku { 2040b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2041b7028ebfSSpencer Ku { 2042b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2043b7028ebfSSpencer Ku return false; 2044b7028ebfSSpencer Ku } 2045b7028ebfSSpencer Ku } 2046b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2047b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2048b7028ebfSSpencer Ku if (!lastMessage.empty()) 2049b7028ebfSSpencer Ku { 2050b7028ebfSSpencer Ku logCount++; 2051b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2052b7028ebfSSpencer Ku { 2053b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2054b7028ebfSSpencer Ku } 2055b7028ebfSSpencer Ku } 2056b7028ebfSSpencer Ku return true; 2057b7028ebfSSpencer Ku } 2058b7028ebfSSpencer Ku 2059b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2060b7028ebfSSpencer Ku const std::string& msg, 20616d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2062b7028ebfSSpencer Ku { 2063b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20649c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 20656d6574c9SJason M. Bills logEntryJson["@odata.id"] = 2066b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" + 20676d6574c9SJason M. Bills logEntryID; 20686d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20696d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20706d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20716d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20726d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20736d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2074b7028ebfSSpencer Ku } 2075b7028ebfSSpencer Ku 2076b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2077b7028ebfSSpencer Ku { 207822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2079b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20801476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20811476687dSEd Tanous [&app](const crow::Request& req, 208222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 208322d268cbSEd Tanous const std::string& systemName) { 20843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 208545ca1b86SEd Tanous { 208645ca1b86SEd Tanous return; 208745ca1b86SEd Tanous } 208822d268cbSEd Tanous if (systemName != "system") 208922d268cbSEd Tanous { 209022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 209122d268cbSEd Tanous systemName); 209222d268cbSEd Tanous return; 209322d268cbSEd Tanous } 2094b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2095b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2096b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2097b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2098b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2099b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2100b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21011476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 21021476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2103b7028ebfSSpencer Ku }); 2104b7028ebfSSpencer Ku } 2105b7028ebfSSpencer Ku 2106b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2107b7028ebfSSpencer Ku { 2108b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 210922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2110b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2111002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2112002d39b4SEd Tanous [&app](const crow::Request& req, 211322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 211422d268cbSEd Tanous const std::string& systemName) { 2115c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2116c937d2bfSEd Tanous .canDelegateTop = true, 2117c937d2bfSEd Tanous .canDelegateSkip = true, 2118c937d2bfSEd Tanous }; 2119c937d2bfSEd Tanous query_param::Query delegatedQuery; 2120c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21213ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2122b7028ebfSSpencer Ku { 2123b7028ebfSSpencer Ku return; 2124b7028ebfSSpencer Ku } 212522d268cbSEd Tanous if (systemName != "system") 212622d268cbSEd Tanous { 212722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 212822d268cbSEd Tanous systemName); 212922d268cbSEd Tanous return; 213022d268cbSEd Tanous } 2131b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2132b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2133b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2134b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2135b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2136b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2137b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21380fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2139b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2140b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2141b7028ebfSSpencer Ku 2142b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2143b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2144b7028ebfSSpencer Ku { 2145b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2146b7028ebfSSpencer Ku return; 2147b7028ebfSSpencer Ku } 21483648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21493648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21505143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2151b7028ebfSSpencer Ku size_t logCount = 0; 2152b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2153b7028ebfSSpencer Ku // control by skip and top. 2154b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21553648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21563648c8beSEd Tanous logCount)) 2157b7028ebfSSpencer Ku { 2158b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2159b7028ebfSSpencer Ku return; 2160b7028ebfSSpencer Ku } 2161b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2162b7028ebfSSpencer Ku // log count 216326f6976fSEd Tanous if (logEntries.empty()) 2164b7028ebfSSpencer Ku { 2165b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2166b7028ebfSSpencer Ku return; 2167b7028ebfSSpencer Ku } 216826f6976fSEd Tanous if (!logEntries.empty()) 2169b7028ebfSSpencer Ku { 2170b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2171b7028ebfSSpencer Ku { 21726d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21733648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21743648c8beSEd Tanous hostLogEntry); 21756d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2176b7028ebfSSpencer Ku } 2177b7028ebfSSpencer Ku 2178b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21793648c8beSEd Tanous if (skip + top < logCount) 2180b7028ebfSSpencer Ku { 2181b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 21820fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 21833648c8beSEd Tanous std::to_string(skip + top); 2184b7028ebfSSpencer Ku } 2185b7028ebfSSpencer Ku } 2186b7028ebfSSpencer Ku }); 2187b7028ebfSSpencer Ku } 2188b7028ebfSSpencer Ku 2189b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2190b7028ebfSSpencer Ku { 2191b7028ebfSSpencer Ku BMCWEB_ROUTE( 219222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2193b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2194b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 219545ca1b86SEd Tanous [&app](const crow::Request& req, 2196b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21983ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 219945ca1b86SEd Tanous { 220045ca1b86SEd Tanous return; 220145ca1b86SEd Tanous } 220222d268cbSEd Tanous if (systemName != "system") 220322d268cbSEd Tanous { 220422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 220522d268cbSEd Tanous systemName); 220622d268cbSEd Tanous return; 220722d268cbSEd Tanous } 2208b7028ebfSSpencer Ku const std::string& targetID = param; 2209b7028ebfSSpencer Ku 2210b7028ebfSSpencer Ku uint64_t idInt = 0; 2211ca45aa3cSEd Tanous 2212ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2213ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2214ca45aa3cSEd Tanous 2215ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 22169db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 22179db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2218b7028ebfSSpencer Ku { 22199db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2220b7028ebfSSpencer Ku return; 2221b7028ebfSSpencer Ku } 2222b7028ebfSSpencer Ku 2223b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2224b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2225b7028ebfSSpencer Ku { 2226b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2227b7028ebfSSpencer Ku return; 2228b7028ebfSSpencer Ku } 2229b7028ebfSSpencer Ku 2230b7028ebfSSpencer Ku size_t logCount = 0; 22313648c8beSEd Tanous size_t top = 1; 2232b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2233b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2234b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2235b7028ebfSSpencer Ku // get that entry 2236002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2237002d39b4SEd Tanous logCount)) 2238b7028ebfSSpencer Ku { 2239b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2240b7028ebfSSpencer Ku return; 2241b7028ebfSSpencer Ku } 2242b7028ebfSSpencer Ku 2243b7028ebfSSpencer Ku if (!logEntries.empty()) 2244b7028ebfSSpencer Ku { 22456d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22466d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22476d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2248b7028ebfSSpencer Ku return; 2249b7028ebfSSpencer Ku } 2250b7028ebfSSpencer Ku 2251b7028ebfSSpencer Ku // Requested ID was not found 22529db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2253b7028ebfSSpencer Ku }); 2254b7028ebfSSpencer Ku } 2255b7028ebfSSpencer Ku 2256dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2257fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2258fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22591da66f75SEd Tanous { 22603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 226145ca1b86SEd Tanous { 226245ca1b86SEd Tanous return; 226345ca1b86SEd Tanous } 22647e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22657e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2266e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22671da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2268e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2269e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2270002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2271e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22721da66f75SEd Tanous "Collection of LogServices for this Manager"; 2273002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2274c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2275fdd26906SClaire Weinan 2276c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2277613dabeaSEd Tanous nlohmann::json::object_t journal; 2278613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2279613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2280c4bf6374SJason M. Bills #endif 2281fdd26906SClaire Weinan 2282fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2283fdd26906SClaire Weinan 2284fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 2285*7a1dbc48SGeorge Liu const std::array<const char*, 1> interfaces = { 2286*7a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 2287*7a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 2288*7a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2289fdd26906SClaire Weinan [asyncResp]( 2290*7a1dbc48SGeorge Liu const boost::system::error_code& ec, 2291fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2292fdd26906SClaire Weinan if (ec) 2293fdd26906SClaire Weinan { 2294fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2295dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2296fdd26906SClaire Weinan << ec; 2297fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2298fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2299fdd26906SClaire Weinan return; 2300fdd26906SClaire Weinan } 2301fdd26906SClaire Weinan 2302fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2303fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2304fdd26906SClaire Weinan 2305fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2306fdd26906SClaire Weinan { 2307fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2308fdd26906SClaire Weinan { 2309613dabeaSEd Tanous nlohmann::json::object_t member; 2310613dabeaSEd Tanous member["@odata.id"] = 2311613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2312613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2313fdd26906SClaire Weinan } 2314fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2315fdd26906SClaire Weinan { 2316613dabeaSEd Tanous nlohmann::json::object_t member; 2317613dabeaSEd Tanous member["@odata.id"] = 2318613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2319613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2320fdd26906SClaire Weinan } 2321fdd26906SClaire Weinan } 2322fdd26906SClaire Weinan 2323e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2324fdd26906SClaire Weinan logServiceArrayLocal.size(); 2325*7a1dbc48SGeorge Liu }); 2326fdd26906SClaire Weinan #endif 2327fdd26906SClaire Weinan } 2328fdd26906SClaire Weinan 2329fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2330fdd26906SClaire Weinan { 2331fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2332fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2333fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2334dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2335e1f26343SJason M. Bills } 2336e1f26343SJason M. Bills 23377e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2338e1f26343SJason M. Bills { 23397e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2340ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23417e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 234245ca1b86SEd Tanous [&app](const crow::Request& req, 234345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23457e860f15SJohn Edward Broadbent { 234645ca1b86SEd Tanous return; 234745ca1b86SEd Tanous } 2348e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2349e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23500f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23510f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2352002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2353002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2354c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "BMC Journal"; 2355e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23567c8c4058STejas Patil 23577c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23582b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2359002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23607c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23617c8c4058STejas Patil redfishDateTimeOffset.second; 23627c8c4058STejas Patil 23631476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23641476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23657e860f15SJohn Edward Broadbent }); 2366e1f26343SJason M. Bills } 2367e1f26343SJason M. Bills 23683a48b3a2SJason M. Bills static int 23693a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2370e1f26343SJason M. Bills sd_journal* journal, 23713a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2372e1f26343SJason M. Bills { 2373e1f26343SJason M. Bills // Get the Log Entry contents 2374e1f26343SJason M. Bills int ret = 0; 2375e1f26343SJason M. Bills 2376a8fe54f0SJason M. Bills std::string message; 2377a8fe54f0SJason M. Bills std::string_view syslogID; 2378a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2379a8fe54f0SJason M. Bills if (ret < 0) 2380a8fe54f0SJason M. Bills { 2381a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2382a8fe54f0SJason M. Bills << strerror(-ret); 2383a8fe54f0SJason M. Bills } 2384a8fe54f0SJason M. Bills if (!syslogID.empty()) 2385a8fe54f0SJason M. Bills { 2386a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2387a8fe54f0SJason M. Bills } 2388a8fe54f0SJason M. Bills 238939e77504SEd Tanous std::string_view msg; 239016428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2391e1f26343SJason M. Bills if (ret < 0) 2392e1f26343SJason M. Bills { 2393e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2394e1f26343SJason M. Bills return 1; 2395e1f26343SJason M. Bills } 2396a8fe54f0SJason M. Bills message += std::string(msg); 2397e1f26343SJason M. Bills 2398e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2399271584abSEd Tanous long int severity = 8; // Default to an invalid priority 240016428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2401e1f26343SJason M. Bills if (ret < 0) 2402e1f26343SJason M. Bills { 2403e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2404e1f26343SJason M. Bills } 2405e1f26343SJason M. Bills 2406e1f26343SJason M. Bills // Get the Created time from the timestamp 240716428a1aSJason M. Bills std::string entryTimeStr; 240816428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2409e1f26343SJason M. Bills { 241016428a1aSJason M. Bills return 1; 2411e1f26343SJason M. Bills } 2412e1f26343SJason M. Bills 2413e1f26343SJason M. Bills // Fill in the log entry with the gathered data 24149c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 241584afc48bSJason M. Bills bmcJournalLogEntryJson["@odata.id"] = 241684afc48bSJason M. Bills "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" + 241784afc48bSJason M. Bills bmcJournalLogEntryID; 241884afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 241984afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 242084afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 242184afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 242284afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2423738c1e61SPatrick Williams : severity <= 4 ? "Warning" 242484afc48bSJason M. Bills : "OK"; 242584afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 242684afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2427e1f26343SJason M. Bills return 0; 2428e1f26343SJason M. Bills } 2429e1f26343SJason M. Bills 24307e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2431e1f26343SJason M. Bills { 24327e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2433ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2434002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2435002d39b4SEd Tanous [&app](const crow::Request& req, 2436002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2437c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2438c937d2bfSEd Tanous .canDelegateTop = true, 2439c937d2bfSEd Tanous .canDelegateSkip = true, 2440c937d2bfSEd Tanous }; 2441c937d2bfSEd Tanous query_param::Query delegatedQuery; 2442c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24433ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2444193ad2faSJason M. Bills { 2445193ad2faSJason M. Bills return; 2446193ad2faSJason M. Bills } 24473648c8beSEd Tanous 24483648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24495143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24503648c8beSEd Tanous 24517e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24527e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2453e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2454e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24550f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24560f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2457e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2458e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2459e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24600fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2461e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2462e1f26343SJason M. Bills 24637e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24647e860f15SJohn Edward Broadbent // unique ID for each entry 2465e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2466e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2467e1f26343SJason M. Bills if (ret < 0) 2468e1f26343SJason M. Bills { 2469002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2470f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2471e1f26343SJason M. Bills return; 2472e1f26343SJason M. Bills } 24730fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 24740fda0f12SGeorge Liu journalTmp, sd_journal_close); 2475e1f26343SJason M. Bills journalTmp = nullptr; 2476b01bf299SEd Tanous uint64_t entryCount = 0; 2477e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2478e85d6b16SJason M. Bills bool firstEntry = true; 2479e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2480e1f26343SJason M. Bills { 2481193ad2faSJason M. Bills entryCount++; 24827e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 24837e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 24843648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2485193ad2faSJason M. Bills { 2486193ad2faSJason M. Bills continue; 2487193ad2faSJason M. Bills } 2488193ad2faSJason M. Bills 248916428a1aSJason M. Bills std::string idStr; 2490e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2491e1f26343SJason M. Bills { 2492e1f26343SJason M. Bills continue; 2493e1f26343SJason M. Bills } 2494e85d6b16SJason M. Bills firstEntry = false; 2495e85d6b16SJason M. Bills 24963a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2497c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2498c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2499e1f26343SJason M. Bills { 2500f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2501e1f26343SJason M. Bills return; 2502e1f26343SJason M. Bills } 25033a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2504e1f26343SJason M. Bills } 2505193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 25063648c8beSEd Tanous if (skip + top < entryCount) 2507193ad2faSJason M. Bills { 2508193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 25090fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 25103648c8beSEd Tanous std::to_string(skip + top); 2511193ad2faSJason M. Bills } 25127e860f15SJohn Edward Broadbent }); 2513e1f26343SJason M. Bills } 2514e1f26343SJason M. Bills 25157e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2516e1f26343SJason M. Bills { 25177e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 25187e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2519ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 25207e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 252145ca1b86SEd Tanous [&app](const crow::Request& req, 25227e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25237e860f15SJohn Edward Broadbent const std::string& entryID) { 25243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 252545ca1b86SEd Tanous { 252645ca1b86SEd Tanous return; 252745ca1b86SEd Tanous } 2528e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2529e1f26343SJason M. Bills uint64_t ts = 0; 2530271584abSEd Tanous uint64_t index = 0; 25318d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2532e1f26343SJason M. Bills { 253316428a1aSJason M. Bills return; 2534e1f26343SJason M. Bills } 2535e1f26343SJason M. Bills 2536e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2537e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2538e1f26343SJason M. Bills if (ret < 0) 2539e1f26343SJason M. Bills { 2540002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2541f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2542e1f26343SJason M. Bills return; 2543e1f26343SJason M. Bills } 2544002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2545002d39b4SEd Tanous journalTmp, sd_journal_close); 2546e1f26343SJason M. Bills journalTmp = nullptr; 25477e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25487e860f15SJohn Edward Broadbent // index tracking the unique ID 2549af07e3f5SJason M. Bills std::string idStr; 2550af07e3f5SJason M. Bills bool firstEntry = true; 2551e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25522056b6d1SManojkiran Eda if (ret < 0) 25532056b6d1SManojkiran Eda { 25542056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25552056b6d1SManojkiran Eda << strerror(-ret); 25562056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25572056b6d1SManojkiran Eda return; 25582056b6d1SManojkiran Eda } 2559271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2560e1f26343SJason M. Bills { 2561e1f26343SJason M. Bills sd_journal_next(journal.get()); 2562af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2563af07e3f5SJason M. Bills { 2564af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2565af07e3f5SJason M. Bills return; 2566af07e3f5SJason M. Bills } 2567af07e3f5SJason M. Bills firstEntry = false; 2568af07e3f5SJason M. Bills } 2569c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2570af07e3f5SJason M. Bills if (idStr != entryID) 2571c4bf6374SJason M. Bills { 25729db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2573c4bf6374SJason M. Bills return; 2574c4bf6374SJason M. Bills } 2575c4bf6374SJason M. Bills 25763a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2577c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 25783a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2579e1f26343SJason M. Bills { 2580f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2581e1f26343SJason M. Bills return; 2582e1f26343SJason M. Bills } 2583d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 25847e860f15SJohn Edward Broadbent }); 2585c9bb6861Sraviteja-b } 2586c9bb6861Sraviteja-b 2587fdd26906SClaire Weinan inline void 2588fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2589fdd26906SClaire Weinan const std::string& dumpType) 2590c9bb6861Sraviteja-b { 2591fdd26906SClaire Weinan std::string dumpPath; 2592fdd26906SClaire Weinan std::string overWritePolicy; 2593fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2594fdd26906SClaire Weinan 2595fdd26906SClaire Weinan if (dumpType == "BMC") 259645ca1b86SEd Tanous { 2597fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2598fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2599fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2600fdd26906SClaire Weinan } 2601fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2602fdd26906SClaire Weinan { 2603fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2604fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2605fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2606fdd26906SClaire Weinan } 2607fdd26906SClaire Weinan else if (dumpType == "System") 2608fdd26906SClaire Weinan { 2609fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2610fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2611fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2612fdd26906SClaire Weinan } 2613fdd26906SClaire Weinan else 2614fdd26906SClaire Weinan { 2615fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2616fdd26906SClaire Weinan << dumpType; 2617fdd26906SClaire Weinan messages::internalError(asyncResp->res); 261845ca1b86SEd Tanous return; 261945ca1b86SEd Tanous } 2620fdd26906SClaire Weinan 2621fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2622fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2623c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2624fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2625fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2626fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 26277c8c4058STejas Patil 26287c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 26292b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 26300fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 26317c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 26327c8c4058STejas Patil redfishDateTimeOffset.second; 26337c8c4058STejas Patil 2634fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2635002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 2636fdd26906SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 2637fdd26906SClaire Weinan 2638fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2639fdd26906SClaire Weinan { 2640002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26411476687dSEd Tanous ["target"] = 2642fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2643fdd26906SClaire Weinan } 2644c9bb6861Sraviteja-b } 2645c9bb6861Sraviteja-b 2646fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2647fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2648fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 26497e860f15SJohn Edward Broadbent { 26503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 265145ca1b86SEd Tanous { 265245ca1b86SEd Tanous return; 265345ca1b86SEd Tanous } 2654fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2655fdd26906SClaire Weinan } 2656c9bb6861Sraviteja-b 265722d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 265822d268cbSEd Tanous crow::App& app, const crow::Request& req, 265922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 266022d268cbSEd Tanous const std::string& chassisId) 266122d268cbSEd Tanous { 266222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 266322d268cbSEd Tanous { 266422d268cbSEd Tanous return; 266522d268cbSEd Tanous } 266622d268cbSEd Tanous if (chassisId != "system") 266722d268cbSEd Tanous { 266822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 266922d268cbSEd Tanous return; 267022d268cbSEd Tanous } 267122d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 267222d268cbSEd Tanous } 267322d268cbSEd Tanous 2674fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2675fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2676fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2677fdd26906SClaire Weinan { 2678fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2679fdd26906SClaire Weinan { 2680fdd26906SClaire Weinan return; 2681fdd26906SClaire Weinan } 2682fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2683fdd26906SClaire Weinan } 2684fdd26906SClaire Weinan 268522d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 268622d268cbSEd Tanous crow::App& app, const crow::Request& req, 268722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 268822d268cbSEd Tanous const std::string& chassisId) 268922d268cbSEd Tanous { 269022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 269122d268cbSEd Tanous { 269222d268cbSEd Tanous return; 269322d268cbSEd Tanous } 269422d268cbSEd Tanous if (chassisId != "system") 269522d268cbSEd Tanous { 269622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 269722d268cbSEd Tanous return; 269822d268cbSEd Tanous } 269922d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 270022d268cbSEd Tanous } 270122d268cbSEd Tanous 2702fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2703fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2704fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2705fdd26906SClaire Weinan const std::string& dumpId) 2706fdd26906SClaire Weinan { 2707fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2708fdd26906SClaire Weinan { 2709fdd26906SClaire Weinan return; 2710fdd26906SClaire Weinan } 2711fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2712fdd26906SClaire Weinan } 271322d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 271422d268cbSEd Tanous crow::App& app, const crow::Request& req, 271522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 271622d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 271722d268cbSEd Tanous { 271822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 271922d268cbSEd Tanous { 272022d268cbSEd Tanous return; 272122d268cbSEd Tanous } 272222d268cbSEd Tanous if (chassisId != "system") 272322d268cbSEd Tanous { 272422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 272522d268cbSEd Tanous return; 272622d268cbSEd Tanous } 272722d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 272822d268cbSEd Tanous } 2729fdd26906SClaire Weinan 2730fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2731fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2732fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2733fdd26906SClaire Weinan const std::string& dumpId) 2734fdd26906SClaire Weinan { 2735fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2736fdd26906SClaire Weinan { 2737fdd26906SClaire Weinan return; 2738fdd26906SClaire Weinan } 2739fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2740fdd26906SClaire Weinan } 2741fdd26906SClaire Weinan 274222d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 274322d268cbSEd Tanous crow::App& app, const crow::Request& req, 274422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 274522d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 274622d268cbSEd Tanous { 274722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 274822d268cbSEd Tanous { 274922d268cbSEd Tanous return; 275022d268cbSEd Tanous } 275122d268cbSEd Tanous if (chassisId != "system") 275222d268cbSEd Tanous { 275322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 275422d268cbSEd Tanous return; 275522d268cbSEd Tanous } 275622d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 275722d268cbSEd Tanous } 275822d268cbSEd Tanous 2759fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2760fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2761fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2762fdd26906SClaire Weinan { 2763fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2764fdd26906SClaire Weinan { 2765fdd26906SClaire Weinan return; 2766fdd26906SClaire Weinan } 2767fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2768fdd26906SClaire Weinan } 2769fdd26906SClaire Weinan 277022d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 277122d268cbSEd Tanous crow::App& app, const crow::Request& req, 277222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 277322d268cbSEd Tanous const std::string& chassisId) 277422d268cbSEd Tanous { 277522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 277622d268cbSEd Tanous { 277722d268cbSEd Tanous return; 277822d268cbSEd Tanous } 277922d268cbSEd Tanous if (chassisId != "system") 278022d268cbSEd Tanous { 278122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 278222d268cbSEd Tanous return; 278322d268cbSEd Tanous } 278422d268cbSEd Tanous createDump(asyncResp, req, "System"); 278522d268cbSEd Tanous } 278622d268cbSEd Tanous 2787fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2788fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2789fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2790fdd26906SClaire Weinan { 2791fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2792fdd26906SClaire Weinan { 2793fdd26906SClaire Weinan return; 2794fdd26906SClaire Weinan } 2795fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2796fdd26906SClaire Weinan } 2797fdd26906SClaire Weinan 279822d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 279922d268cbSEd Tanous crow::App& app, const crow::Request& req, 280022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 280122d268cbSEd Tanous const std::string& chassisId) 280222d268cbSEd Tanous { 280322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 280422d268cbSEd Tanous { 280522d268cbSEd Tanous return; 280622d268cbSEd Tanous } 280722d268cbSEd Tanous if (chassisId != "system") 280822d268cbSEd Tanous { 280922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 281022d268cbSEd Tanous return; 281122d268cbSEd Tanous } 281222d268cbSEd Tanous clearDump(asyncResp, "System"); 281322d268cbSEd Tanous } 281422d268cbSEd Tanous 2815fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2816fdd26906SClaire Weinan { 2817fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2818fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2819fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2820fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2821fdd26906SClaire Weinan } 2822fdd26906SClaire Weinan 2823fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2824fdd26906SClaire Weinan { 2825fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2826fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2827fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2828fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2829c9bb6861Sraviteja-b } 2830c9bb6861Sraviteja-b 28317e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2832c9bb6861Sraviteja-b { 28337e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28347e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2835ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2836fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2837fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2838fdd26906SClaire Weinan 28397e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28407e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2841ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2842fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2843fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2844c9bb6861Sraviteja-b } 2845c9bb6861Sraviteja-b 28467e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2847c9bb6861Sraviteja-b { 28480fda0f12SGeorge Liu BMCWEB_ROUTE( 28490fda0f12SGeorge Liu app, 28500fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2851ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28527e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2853fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2854fdd26906SClaire Weinan std::ref(app), "BMC")); 2855a43be80fSAsmitha Karunanithi } 2856a43be80fSAsmitha Karunanithi 28577e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 285880319af1SAsmitha Karunanithi { 28590fda0f12SGeorge Liu BMCWEB_ROUTE( 28600fda0f12SGeorge Liu app, 28610fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2862ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2863fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2864fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 286545ca1b86SEd Tanous } 2866fdd26906SClaire Weinan 2867fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2868fdd26906SClaire Weinan { 2869fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2870fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2871fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2872fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2873fdd26906SClaire Weinan } 2874fdd26906SClaire Weinan 2875fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2876fdd26906SClaire Weinan { 2877fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2878fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2879fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2880fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2881fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2882fdd26906SClaire Weinan } 2883fdd26906SClaire Weinan 2884fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2885fdd26906SClaire Weinan { 2886fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2887fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2888fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2889fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2890fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2891fdd26906SClaire Weinan 2892fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2893fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2894fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2895fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2896fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2897fdd26906SClaire Weinan } 2898fdd26906SClaire Weinan 2899fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2900fdd26906SClaire Weinan { 2901fdd26906SClaire Weinan BMCWEB_ROUTE( 2902fdd26906SClaire Weinan app, 2903fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2904fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2905fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2906fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 29075cb1dd27SAsmitha Karunanithi } 29085cb1dd27SAsmitha Karunanithi 29097e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 29105cb1dd27SAsmitha Karunanithi { 291122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2912ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 29136ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 291422d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 29155cb1dd27SAsmitha Karunanithi } 29165cb1dd27SAsmitha Karunanithi 29177e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 29187e860f15SJohn Edward Broadbent { 291922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2920ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 292122d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 292222d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 292322d268cbSEd Tanous std::ref(app))); 29245cb1dd27SAsmitha Karunanithi } 29255cb1dd27SAsmitha Karunanithi 29267e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 29275cb1dd27SAsmitha Karunanithi { 29287e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 292922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2930ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29316ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 293222d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29338d1b46d7Szhanghch05 29347e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 293522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2936ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29376ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 293822d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29395cb1dd27SAsmitha Karunanithi } 2940c9bb6861Sraviteja-b 29417e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2942c9bb6861Sraviteja-b { 29430fda0f12SGeorge Liu BMCWEB_ROUTE( 29440fda0f12SGeorge Liu app, 294522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2946ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 294722d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 294822d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 294922d268cbSEd Tanous std::ref(app))); 2950a43be80fSAsmitha Karunanithi } 2951a43be80fSAsmitha Karunanithi 29527e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2953a43be80fSAsmitha Karunanithi { 29540fda0f12SGeorge Liu BMCWEB_ROUTE( 29550fda0f12SGeorge Liu app, 295622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2957ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29586ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 295922d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2960013487e5Sraviteja-b } 2961013487e5Sraviteja-b 29627e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29631da66f75SEd Tanous { 29643946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29653946028dSAppaRao Puli // method for security reasons. 29661da66f75SEd Tanous /** 29671da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29681da66f75SEd Tanous */ 296922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2970ed398213SEd Tanous // This is incorrect, should be: 2971ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2972432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2973002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2974002d39b4SEd Tanous [&app](const crow::Request& req, 297522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297622d268cbSEd Tanous const std::string& systemName) { 29773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 297845ca1b86SEd Tanous { 297945ca1b86SEd Tanous return; 298045ca1b86SEd Tanous } 298122d268cbSEd Tanous if (systemName != "system") 298222d268cbSEd Tanous { 298322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 298422d268cbSEd Tanous systemName); 298522d268cbSEd Tanous return; 298622d268cbSEd Tanous } 298722d268cbSEd Tanous 29887e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29897e860f15SJohn Edward Broadbent // SubRoute 29900f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2991424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 2992e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 29938e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 29944f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 29954f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 29964f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 2997e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 2998e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 29997c8c4058STejas Patil 30007c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 30012b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 30027c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 30037c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 30047c8c4058STejas Patil redfishDateTimeOffset.second; 30057c8c4058STejas Patil 30061476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 30071476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3008002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 30091476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3010002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 30111476687dSEd Tanous ["target"] = 30121476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 30137e860f15SJohn Edward Broadbent }); 30141da66f75SEd Tanous } 30151da66f75SEd Tanous 30167e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30175b61b5e8SJason M. Bills { 30180fda0f12SGeorge Liu BMCWEB_ROUTE( 30190fda0f12SGeorge Liu app, 302022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3021ed398213SEd Tanous // This is incorrect, should be: 3022ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3023432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30247e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 302545ca1b86SEd Tanous [&app](const crow::Request& req, 302622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 302722d268cbSEd Tanous const std::string& systemName) { 30283ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 302945ca1b86SEd Tanous { 303045ca1b86SEd Tanous return; 303145ca1b86SEd Tanous } 303222d268cbSEd Tanous if (systemName != "system") 303322d268cbSEd Tanous { 303422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 303522d268cbSEd Tanous systemName); 303622d268cbSEd Tanous return; 303722d268cbSEd Tanous } 30385b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30395b61b5e8SJason M. Bills [asyncResp](const boost::system::error_code ec, 3040cb13a392SEd Tanous const std::string&) { 30415b61b5e8SJason M. Bills if (ec) 30425b61b5e8SJason M. Bills { 30435b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30445b61b5e8SJason M. Bills return; 30455b61b5e8SJason M. Bills } 30465b61b5e8SJason M. Bills messages::success(asyncResp->res); 30475b61b5e8SJason M. Bills }, 3048002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30497e860f15SJohn Edward Broadbent }); 30505b61b5e8SJason M. Bills } 30515b61b5e8SJason M. Bills 30528d1b46d7Szhanghch05 static void 30538d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30548d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3055e855dd28SJason M. Bills { 3056043a0536SJohnathan Mantey auto getStoredLogCallback = 3057b9d36b47SEd Tanous [asyncResp, logID, 3058b9d36b47SEd Tanous &logEntryJson](const boost::system::error_code ec, 3059b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3060e855dd28SJason M. Bills if (ec) 3061e855dd28SJason M. Bills { 3062e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 30631ddcf01aSJason M. Bills if (ec.value() == 30641ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30651ddcf01aSJason M. Bills { 3066002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30671ddcf01aSJason M. Bills } 30681ddcf01aSJason M. Bills else 30691ddcf01aSJason M. Bills { 3070e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30711ddcf01aSJason M. Bills } 3072e855dd28SJason M. Bills return; 3073e855dd28SJason M. Bills } 3074043a0536SJohnathan Mantey 3075043a0536SJohnathan Mantey std::string timestamp{}; 3076043a0536SJohnathan Mantey std::string filename{}; 3077043a0536SJohnathan Mantey std::string logfile{}; 30782c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3079043a0536SJohnathan Mantey 3080043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3081e855dd28SJason M. Bills { 30829db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3083e855dd28SJason M. Bills return; 3084e855dd28SJason M. Bills } 3085e855dd28SJason M. Bills 3086043a0536SJohnathan Mantey std::string crashdumpURI = 3087e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3088043a0536SJohnathan Mantey logID + "/" + filename; 308984afc48bSJason M. Bills nlohmann::json::object_t logEntry; 30909c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 309184afc48bSJason M. Bills logEntry["@odata.id"] = 309284afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID; 309384afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 309484afc48bSJason M. Bills logEntry["Id"] = logID; 309584afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 309684afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 309784afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 309884afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 309984afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 31002b20ef6eSJason M. Bills 31012b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 31022b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 31032b20ef6eSJason M. Bills // directly 31042b20ef6eSJason M. Bills if (logEntryJson.is_array()) 31052b20ef6eSJason M. Bills { 31062b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 31072b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 31082b20ef6eSJason M. Bills logEntryJson.size(); 31092b20ef6eSJason M. Bills } 31102b20ef6eSJason M. Bills else 31112b20ef6eSJason M. Bills { 3112d405bb51SJason M. Bills logEntryJson.update(logEntry); 31132b20ef6eSJason M. Bills } 3114e855dd28SJason M. Bills }; 3115d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3116d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3117d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3118d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3119e855dd28SJason M. Bills } 3120e855dd28SJason M. Bills 31217e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31221da66f75SEd Tanous { 31233946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31243946028dSAppaRao Puli // method for security reasons. 31251da66f75SEd Tanous /** 31261da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31271da66f75SEd Tanous */ 31287e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 312922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3130ed398213SEd Tanous // This is incorrect, should be. 3131ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3132432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3133002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3134002d39b4SEd Tanous [&app](const crow::Request& req, 313522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 313622d268cbSEd Tanous const std::string& systemName) { 31373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 313845ca1b86SEd Tanous { 313945ca1b86SEd Tanous return; 314045ca1b86SEd Tanous } 314122d268cbSEd Tanous if (systemName != "system") 314222d268cbSEd Tanous { 314322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 314422d268cbSEd Tanous systemName); 314522d268cbSEd Tanous return; 314622d268cbSEd Tanous } 314722d268cbSEd Tanous 3148*7a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 3149*7a1dbc48SGeorge Liu crashdumpInterface}; 3150*7a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 3151*7a1dbc48SGeorge Liu "/", 0, interfaces, 3152*7a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 31532b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31541da66f75SEd Tanous if (ec) 31551da66f75SEd Tanous { 31561da66f75SEd Tanous if (ec.value() != 31571da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31581da66f75SEd Tanous { 31591da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 31601da66f75SEd Tanous << ec.message(); 3161f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31621da66f75SEd Tanous return; 31631da66f75SEd Tanous } 31641da66f75SEd Tanous } 3165e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31661da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 31670f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3168424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3169002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3170e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3171424c4176SJason M. Bills "Collection of Crashdump Entries"; 3172002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3173a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31742b20ef6eSJason M. Bills 31752b20ef6eSJason M. Bills for (const std::string& path : resp) 31761da66f75SEd Tanous { 31772b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3178e855dd28SJason M. Bills // Get the log ID 31792b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31802b20ef6eSJason M. Bills if (logID.empty()) 31811da66f75SEd Tanous { 3182e855dd28SJason M. Bills continue; 31831da66f75SEd Tanous } 3184e855dd28SJason M. Bills // Add the log entry to the array 31852b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31862b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31871da66f75SEd Tanous } 3188*7a1dbc48SGeorge Liu }); 31897e860f15SJohn Edward Broadbent }); 31901da66f75SEd Tanous } 31911da66f75SEd Tanous 31927e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 31931da66f75SEd Tanous { 31943946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31953946028dSAppaRao Puli // method for security reasons. 31961da66f75SEd Tanous 31977e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 319822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3199ed398213SEd Tanous // this is incorrect, should be 3200ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3201432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32027e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 320345ca1b86SEd Tanous [&app](const crow::Request& req, 32047e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 320522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 32063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 320745ca1b86SEd Tanous { 320845ca1b86SEd Tanous return; 320945ca1b86SEd Tanous } 321022d268cbSEd Tanous if (systemName != "system") 321122d268cbSEd Tanous { 321222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 321322d268cbSEd Tanous systemName); 321422d268cbSEd Tanous return; 321522d268cbSEd Tanous } 32167e860f15SJohn Edward Broadbent const std::string& logID = param; 3217e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32187e860f15SJohn Edward Broadbent }); 3219e855dd28SJason M. Bills } 3220e855dd28SJason M. Bills 32217e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3222e855dd28SJason M. Bills { 32233946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32243946028dSAppaRao Puli // method for security reasons. 32257e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32267e860f15SJohn Edward Broadbent app, 322722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3228ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32297e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3230a4ce114aSNan Zhou [](const crow::Request& req, 32317e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 323222d268cbSEd Tanous const std::string& systemName, const std::string& logID, 323322d268cbSEd Tanous const std::string& fileName) { 32342a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32352a9beeedSShounak Mitra // Redfish resource. 323622d268cbSEd Tanous 323722d268cbSEd Tanous if (systemName != "system") 323822d268cbSEd Tanous { 323922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 324022d268cbSEd Tanous systemName); 324122d268cbSEd Tanous return; 324222d268cbSEd Tanous } 324322d268cbSEd Tanous 3244043a0536SJohnathan Mantey auto getStoredLogCallback = 3245002d39b4SEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))]( 3246abf2add6SEd Tanous const boost::system::error_code ec, 3247002d39b4SEd Tanous const std::vector< 3248002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32497e860f15SJohn Edward Broadbent resp) { 32501da66f75SEd Tanous if (ec) 32511da66f75SEd Tanous { 3252002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3253f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32541da66f75SEd Tanous return; 32551da66f75SEd Tanous } 3256e855dd28SJason M. Bills 3257043a0536SJohnathan Mantey std::string dbusFilename{}; 3258043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3259043a0536SJohnathan Mantey std::string dbusFilepath{}; 3260043a0536SJohnathan Mantey 3261002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3262002d39b4SEd Tanous dbusFilepath); 3263043a0536SJohnathan Mantey 3264043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3265043a0536SJohnathan Mantey dbusFilepath.empty()) 32661da66f75SEd Tanous { 32679db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32681da66f75SEd Tanous return; 32691da66f75SEd Tanous } 3270e855dd28SJason M. Bills 3271043a0536SJohnathan Mantey // Verify the file name parameter is correct 3272043a0536SJohnathan Mantey if (fileName != dbusFilename) 3273043a0536SJohnathan Mantey { 32749db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3275043a0536SJohnathan Mantey return; 3276043a0536SJohnathan Mantey } 3277043a0536SJohnathan Mantey 3278043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3279043a0536SJohnathan Mantey { 32809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3281043a0536SJohnathan Mantey return; 3282043a0536SJohnathan Mantey } 3283002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3284002d39b4SEd Tanous asyncResp->res.body() = 3285002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3286043a0536SJohnathan Mantey 32877e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32887e860f15SJohn Edward Broadbent // from a browser 3289d9f6c621SEd Tanous asyncResp->res.addHeader( 3290d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 32911da66f75SEd Tanous }; 3292d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3293d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3294d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3295d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 32967e860f15SJohn Edward Broadbent }); 32971da66f75SEd Tanous } 32981da66f75SEd Tanous 3299c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3300c5a4c82aSJason M. Bills { 3301c5a4c82aSJason M. Bills onDemand, 3302c5a4c82aSJason M. Bills telemetry, 3303c5a4c82aSJason M. Bills invalid, 3304c5a4c82aSJason M. Bills }; 3305c5a4c82aSJason M. Bills 3306f7725d79SEd Tanous inline OEMDiagnosticType 3307f7725d79SEd Tanous getOEMDiagnosticType(const std::string_view& oemDiagStr) 3308c5a4c82aSJason M. Bills { 3309c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3310c5a4c82aSJason M. Bills { 3311c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3312c5a4c82aSJason M. Bills } 3313c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3314c5a4c82aSJason M. Bills { 3315c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3316c5a4c82aSJason M. Bills } 3317c5a4c82aSJason M. Bills 3318c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3319c5a4c82aSJason M. Bills } 3320c5a4c82aSJason M. Bills 33217e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33221da66f75SEd Tanous { 33233946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33243946028dSAppaRao Puli // method for security reasons. 33250fda0f12SGeorge Liu BMCWEB_ROUTE( 33260fda0f12SGeorge Liu app, 332722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3328ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3329ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3330432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3331002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3332002d39b4SEd Tanous [&app](const crow::Request& req, 333322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 333422d268cbSEd Tanous const std::string& systemName) { 33353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 333645ca1b86SEd Tanous { 333745ca1b86SEd Tanous return; 333845ca1b86SEd Tanous } 333922d268cbSEd Tanous 334022d268cbSEd Tanous if (systemName != "system") 334122d268cbSEd Tanous { 334222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 334322d268cbSEd Tanous systemName); 334422d268cbSEd Tanous return; 334522d268cbSEd Tanous } 334622d268cbSEd Tanous 33478e6c099aSJason M. Bills std::string diagnosticDataType; 33488e6c099aSJason M. Bills std::string oemDiagnosticDataType; 334915ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3350002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3351002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33528e6c099aSJason M. Bills { 33538e6c099aSJason M. Bills return; 33548e6c099aSJason M. Bills } 33558e6c099aSJason M. Bills 33568e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33578e6c099aSJason M. Bills { 33588e6c099aSJason M. Bills BMCWEB_LOG_ERROR 33598e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 33608e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33618e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33628e6c099aSJason M. Bills "CollectDiagnosticData"); 33638e6c099aSJason M. Bills return; 33648e6c099aSJason M. Bills } 33658e6c099aSJason M. Bills 3366c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3367c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3368c5a4c82aSJason M. Bills 3369c5a4c82aSJason M. Bills std::string iface; 3370c5a4c82aSJason M. Bills std::string method; 3371c5a4c82aSJason M. Bills std::string taskMatchStr; 3372c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3373c5a4c82aSJason M. Bills { 3374c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3375c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3376c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3377c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3378c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3379c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3380c5a4c82aSJason M. Bills } 3381c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3382c5a4c82aSJason M. Bills { 3383c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3384c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3385c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3386c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3387c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3388c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3389c5a4c82aSJason M. Bills } 3390c5a4c82aSJason M. Bills else 3391c5a4c82aSJason M. Bills { 3392c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3393c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3394c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3395002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3396002d39b4SEd Tanous "CollectDiagnosticData"); 3397c5a4c82aSJason M. Bills return; 3398c5a4c82aSJason M. Bills } 3399c5a4c82aSJason M. Bills 3400c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3401c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 3402c5a4c82aSJason M. Bills taskMatchStr](const boost::system::error_code ec, 340398be3e39SEd Tanous const std::string&) mutable { 34041da66f75SEd Tanous if (ec) 34051da66f75SEd Tanous { 3406002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 34071da66f75SEd Tanous { 3408f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 34091da66f75SEd Tanous } 34104363d3b2SJason M. Bills else if (ec.value() == 34114363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 34124363d3b2SJason M. Bills { 3413002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3414002d39b4SEd Tanous "60"); 34154363d3b2SJason M. Bills } 34161da66f75SEd Tanous else 34171da66f75SEd Tanous { 3418f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34191da66f75SEd Tanous } 34201da66f75SEd Tanous return; 34211da66f75SEd Tanous } 3422002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 342359d494eeSPatrick Williams [](boost::system::error_code err, sdbusplus::message_t&, 3424002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 342566afe4faSJames Feist if (!err) 342666afe4faSJames Feist { 3427002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3428e5d5006bSJames Feist std::to_string(taskData->index))); 3429831d6b09SJames Feist taskData->state = "Completed"; 343066afe4faSJames Feist } 343132898ceaSJames Feist return task::completed; 343266afe4faSJames Feist }, 3433c5a4c82aSJason M. Bills taskMatchStr); 3434c5a4c82aSJason M. Bills 343546229577SJames Feist task->startTimer(std::chrono::minutes(5)); 343646229577SJames Feist task->populateResp(asyncResp->res); 343798be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34381da66f75SEd Tanous }; 34398e6c099aSJason M. Bills 34401da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3441002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3442002d39b4SEd Tanous iface, method); 34437e860f15SJohn Edward Broadbent }); 34446eda7685SKenny L. Ku } 34456eda7685SKenny L. Ku 3446cb92c03bSAndrew Geissler /** 3447cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3448cb92c03bSAndrew Geissler */ 34497e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3450cb92c03bSAndrew Geissler { 3451cb92c03bSAndrew Geissler /** 3452cb92c03bSAndrew Geissler * Function handles POST method request. 3453cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3454cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3455cb92c03bSAndrew Geissler */ 34567e860f15SJohn Edward Broadbent 34570fda0f12SGeorge Liu BMCWEB_ROUTE( 34580fda0f12SGeorge Liu app, 345922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3460ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34617e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 346245ca1b86SEd Tanous [&app](const crow::Request& req, 346322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 346422d268cbSEd Tanous const std::string& systemName) { 34653ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 346645ca1b86SEd Tanous { 346745ca1b86SEd Tanous return; 346845ca1b86SEd Tanous } 346922d268cbSEd Tanous if (systemName != "system") 347022d268cbSEd Tanous { 347122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 347222d268cbSEd Tanous systemName); 347322d268cbSEd Tanous return; 347422d268cbSEd Tanous } 3475cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3476cb92c03bSAndrew Geissler 3477cb92c03bSAndrew Geissler // Process response from Logging service. 3478002d39b4SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code ec) { 3479002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3480cb92c03bSAndrew Geissler if (ec) 3481cb92c03bSAndrew Geissler { 3482cb92c03bSAndrew Geissler // TODO Handle for specific error code 3483002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3484cb92c03bSAndrew Geissler asyncResp->res.result( 3485cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3486cb92c03bSAndrew Geissler return; 3487cb92c03bSAndrew Geissler } 3488cb92c03bSAndrew Geissler 3489002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3490cb92c03bSAndrew Geissler }; 3491cb92c03bSAndrew Geissler 3492cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3493cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 34942c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3495cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3496cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 34977e860f15SJohn Edward Broadbent }); 3498cb92c03bSAndrew Geissler } 3499a3316fc6SZhikuiRen 3500a3316fc6SZhikuiRen /**************************************************** 3501a3316fc6SZhikuiRen * Redfish PostCode interfaces 3502a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3503a3316fc6SZhikuiRen ******************************************************/ 35047e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3505a3316fc6SZhikuiRen { 350622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3507ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3508002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3509002d39b4SEd Tanous [&app](const crow::Request& req, 351022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 351122d268cbSEd Tanous const std::string& systemName) { 35123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 351345ca1b86SEd Tanous { 351445ca1b86SEd Tanous return; 351545ca1b86SEd Tanous } 351622d268cbSEd Tanous if (systemName != "system") 351722d268cbSEd Tanous { 351822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 351922d268cbSEd Tanous systemName); 352022d268cbSEd Tanous return; 352122d268cbSEd Tanous } 35221476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 35231476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 35241476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 35251476687dSEd Tanous "#LogService.v1_1_0.LogService"; 35261476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35271476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 35281476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log"; 35291476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35301476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35311476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35327c8c4058STejas Patil 35337c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35342b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35350fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35367c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35377c8c4058STejas Patil redfishDateTimeOffset.second; 35387c8c4058STejas Patil 3539a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 35407e860f15SJohn Edward Broadbent {"target", 35410fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 35427e860f15SJohn Edward Broadbent }); 3543a3316fc6SZhikuiRen } 3544a3316fc6SZhikuiRen 35457e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3546a3316fc6SZhikuiRen { 35470fda0f12SGeorge Liu BMCWEB_ROUTE( 35480fda0f12SGeorge Liu app, 354922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3550ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3551ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3552432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35537e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 355445ca1b86SEd Tanous [&app](const crow::Request& req, 355522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 355622d268cbSEd Tanous const std::string& systemName) { 35573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 355845ca1b86SEd Tanous { 355945ca1b86SEd Tanous return; 356045ca1b86SEd Tanous } 356122d268cbSEd Tanous if (systemName != "system") 356222d268cbSEd Tanous { 356322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 356422d268cbSEd Tanous systemName); 356522d268cbSEd Tanous return; 356622d268cbSEd Tanous } 3567a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3568a3316fc6SZhikuiRen 3569a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3570a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3571a3316fc6SZhikuiRen [asyncResp](const boost::system::error_code ec) { 3572a3316fc6SZhikuiRen if (ec) 3573a3316fc6SZhikuiRen { 3574a3316fc6SZhikuiRen // TODO Handle for specific error code 3575002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 35767e860f15SJohn Edward Broadbent << ec; 3577002d39b4SEd Tanous asyncResp->res.result( 3578002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3579a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3580a3316fc6SZhikuiRen return; 3581a3316fc6SZhikuiRen } 3582a3316fc6SZhikuiRen }, 358315124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 358415124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3585a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35867e860f15SJohn Edward Broadbent }); 3587a3316fc6SZhikuiRen } 3588a3316fc6SZhikuiRen 35896f284d24SJiaqing Zhao /** 35906f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 35916f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 35926f284d24SJiaqing Zhao * 35936f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 35946f284d24SJiaqing Zhao * @param[out] currentValue Current value 35956f284d24SJiaqing Zhao * @param[out] index Index value 35966f284d24SJiaqing Zhao * 35976f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 35986f284d24SJiaqing Zhao */ 35996f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 36006f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 36016f284d24SJiaqing Zhao { 36026f284d24SJiaqing Zhao std::vector<std::string> split; 36036f284d24SJiaqing Zhao boost::algorithm::split(split, postCodeID, boost::is_any_of("-")); 36046f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 36056f284d24SJiaqing Zhao { 36066f284d24SJiaqing Zhao return false; 36076f284d24SJiaqing Zhao } 36086f284d24SJiaqing Zhao 36096f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36106f284d24SJiaqing Zhao const char* start = split[0].data() + 1; 36116f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36126f284d24SJiaqing Zhao const char* end = split[0].data() + split[0].size(); 36136f284d24SJiaqing Zhao auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 36146f284d24SJiaqing Zhao 36156f284d24SJiaqing Zhao if (ptrIndex != end || ecIndex != std::errc()) 36166f284d24SJiaqing Zhao { 36176f284d24SJiaqing Zhao return false; 36186f284d24SJiaqing Zhao } 36196f284d24SJiaqing Zhao 36206f284d24SJiaqing Zhao start = split[1].data(); 36216f284d24SJiaqing Zhao 36226f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36236f284d24SJiaqing Zhao end = split[1].data() + split[1].size(); 36246f284d24SJiaqing Zhao auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 36256f284d24SJiaqing Zhao 36266f284d24SJiaqing Zhao return ptrValue == end && ecValue == std::errc(); 36276f284d24SJiaqing Zhao } 36286f284d24SJiaqing Zhao 36296f284d24SJiaqing Zhao static bool fillPostCodeEntry( 36308d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 36316c9a279eSManojkiran Eda const boost::container::flat_map< 36326c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3633a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3634a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3635a3316fc6SZhikuiRen { 3636a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3637fffb8c1fSEd Tanous const registries::Message* message = 3638fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3639a3316fc6SZhikuiRen 3640a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3641a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 36426c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36436c9a279eSManojkiran Eda code : postcode) 3644a3316fc6SZhikuiRen { 3645a3316fc6SZhikuiRen currentCodeIndex++; 3646a3316fc6SZhikuiRen std::string postcodeEntryID = 3647a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3648a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3649a3316fc6SZhikuiRen 3650a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3651a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3652a3316fc6SZhikuiRen 3653a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3654a3316fc6SZhikuiRen { // already incremented 3655a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3656a3316fc6SZhikuiRen } 3657a3316fc6SZhikuiRen else 3658a3316fc6SZhikuiRen { 3659a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3660a3316fc6SZhikuiRen } 3661a3316fc6SZhikuiRen 3662a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3663a3316fc6SZhikuiRen // not fall between top and skip 3664a3316fc6SZhikuiRen if ((codeIndex == 0) && 3665a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3666a3316fc6SZhikuiRen { 3667a3316fc6SZhikuiRen continue; 3668a3316fc6SZhikuiRen } 3669a3316fc6SZhikuiRen 36704e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3671a3316fc6SZhikuiRen // currentIndex 3672a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3673a3316fc6SZhikuiRen { 3674a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3675a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3676a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3677a3316fc6SZhikuiRen continue; 3678a3316fc6SZhikuiRen } 3679a3316fc6SZhikuiRen 3680a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3681a3316fc6SZhikuiRen // index 3682a3316fc6SZhikuiRen 3683a3316fc6SZhikuiRen // Get the Created time from the timestamp 3684a3316fc6SZhikuiRen std::string entryTimeStr; 36851d8782e7SNan Zhou entryTimeStr = 36862b82937eSEd Tanous redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000); 3687a3316fc6SZhikuiRen 3688a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3689a3316fc6SZhikuiRen std::ostringstream hexCode; 3690a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 36916c9a279eSManojkiran Eda << std::get<0>(code.second); 3692a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3693a3316fc6SZhikuiRen // Set Fixed -Point Notation 3694a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3695a3316fc6SZhikuiRen // Set precision to 4 digits 3696a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3697a3316fc6SZhikuiRen // Add double to stream 3698a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3699a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3700a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3701a3316fc6SZhikuiRen 3702a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3703a3316fc6SZhikuiRen std::string msg; 3704a3316fc6SZhikuiRen if (message != nullptr) 3705a3316fc6SZhikuiRen { 3706a3316fc6SZhikuiRen msg = message->message; 3707a3316fc6SZhikuiRen 3708a3316fc6SZhikuiRen // fill in this post code value 3709a3316fc6SZhikuiRen int i = 0; 3710a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3711a3316fc6SZhikuiRen { 3712a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3713a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3714a3316fc6SZhikuiRen if (argPos != std::string::npos) 3715a3316fc6SZhikuiRen { 3716a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3717a3316fc6SZhikuiRen } 3718a3316fc6SZhikuiRen } 3719a3316fc6SZhikuiRen } 3720a3316fc6SZhikuiRen 3721d4342a92STim Lee // Get Severity template from message registry 3722d4342a92STim Lee std::string severity; 3723d4342a92STim Lee if (message != nullptr) 3724d4342a92STim Lee { 37255f2b84eeSEd Tanous severity = message->messageSeverity; 3726d4342a92STim Lee } 3727d4342a92STim Lee 37286f284d24SJiaqing Zhao // Format entry 37296f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37309c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 373184afc48bSJason M. Bills bmcLogEntry["@odata.id"] = 37320fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 373384afc48bSJason M. Bills postcodeEntryID; 373484afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 373584afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 373684afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 373784afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 373884afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 373984afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 374084afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 374184afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3742647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3743647b3cdcSGeorge Liu { 3744647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3745647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3746647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3747647b3cdcSGeorge Liu } 37486f284d24SJiaqing Zhao 37496f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 37506f284d24SJiaqing Zhao // that entry in this case 37516f284d24SJiaqing Zhao if (codeIndex != 0) 37526f284d24SJiaqing Zhao { 37536f284d24SJiaqing Zhao aResp->res.jsonValue.update(bmcLogEntry); 37546f284d24SJiaqing Zhao return true; 3755a3316fc6SZhikuiRen } 37566f284d24SJiaqing Zhao 37576f284d24SJiaqing Zhao nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 37586f284d24SJiaqing Zhao logEntryArray.push_back(std::move(bmcLogEntry)); 37596f284d24SJiaqing Zhao } 37606f284d24SJiaqing Zhao 37616f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 37626f284d24SJiaqing Zhao return false; 3763a3316fc6SZhikuiRen } 3764a3316fc6SZhikuiRen 37658d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 37666f284d24SJiaqing Zhao const std::string& entryId) 3767a3316fc6SZhikuiRen { 37686f284d24SJiaqing Zhao uint16_t bootIndex = 0; 37696f284d24SJiaqing Zhao uint64_t codeIndex = 0; 37706f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 37716f284d24SJiaqing Zhao { 37726f284d24SJiaqing Zhao // Requested ID was not found 37736f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 37746f284d24SJiaqing Zhao return; 37756f284d24SJiaqing Zhao } 37766f284d24SJiaqing Zhao 37776f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 37786f284d24SJiaqing Zhao { 37796f284d24SJiaqing Zhao // 0 is an invalid index 37806f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 37816f284d24SJiaqing Zhao return; 37826f284d24SJiaqing Zhao } 37836f284d24SJiaqing Zhao 3784a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 37856f284d24SJiaqing Zhao [aResp, entryId, bootIndex, 37866c9a279eSManojkiran Eda codeIndex](const boost::system::error_code ec, 37876c9a279eSManojkiran Eda const boost::container::flat_map< 37886c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 37896c9a279eSManojkiran Eda postcode) { 3790a3316fc6SZhikuiRen if (ec) 3791a3316fc6SZhikuiRen { 3792a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3793a3316fc6SZhikuiRen messages::internalError(aResp->res); 3794a3316fc6SZhikuiRen return; 3795a3316fc6SZhikuiRen } 3796a3316fc6SZhikuiRen 3797a3316fc6SZhikuiRen if (postcode.empty()) 3798a3316fc6SZhikuiRen { 37996f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 3800a3316fc6SZhikuiRen return; 3801a3316fc6SZhikuiRen } 3802a3316fc6SZhikuiRen 38036f284d24SJiaqing Zhao if (!fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex)) 38046f284d24SJiaqing Zhao { 38056f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 38066f284d24SJiaqing Zhao return; 38076f284d24SJiaqing Zhao } 3808a3316fc6SZhikuiRen }, 380915124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 381015124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3811a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3812a3316fc6SZhikuiRen bootIndex); 3813a3316fc6SZhikuiRen } 3814a3316fc6SZhikuiRen 38158d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3816a3316fc6SZhikuiRen const uint16_t bootIndex, 3817a3316fc6SZhikuiRen const uint16_t bootCount, 38183648c8beSEd Tanous const uint64_t entryCount, size_t skip, 38193648c8beSEd Tanous size_t top) 3820a3316fc6SZhikuiRen { 3821a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3822a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 3823a3316fc6SZhikuiRen top](const boost::system::error_code ec, 38246c9a279eSManojkiran Eda const boost::container::flat_map< 38256c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38266c9a279eSManojkiran Eda postcode) { 3827a3316fc6SZhikuiRen if (ec) 3828a3316fc6SZhikuiRen { 3829a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3830a3316fc6SZhikuiRen messages::internalError(aResp->res); 3831a3316fc6SZhikuiRen return; 3832a3316fc6SZhikuiRen } 3833a3316fc6SZhikuiRen 3834a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3835a3316fc6SZhikuiRen if (!postcode.empty()) 3836a3316fc6SZhikuiRen { 3837a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38383648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3839a3316fc6SZhikuiRen { 38403648c8beSEd Tanous uint64_t thisBootSkip = 38413648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 38423648c8beSEd Tanous entryCount; 3843a3316fc6SZhikuiRen uint64_t thisBootTop = 38443648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38453648c8beSEd Tanous entryCount; 3846a3316fc6SZhikuiRen 3847002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3848002d39b4SEd Tanous thisBootTop); 3849a3316fc6SZhikuiRen } 3850a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3851a3316fc6SZhikuiRen } 3852a3316fc6SZhikuiRen 3853a3316fc6SZhikuiRen // continue to previous bootIndex 3854a3316fc6SZhikuiRen if (bootIndex < bootCount) 3855a3316fc6SZhikuiRen { 3856a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3857a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3858a3316fc6SZhikuiRen } 385981584abeSJiaqing Zhao else if (skip + top < endCount) 3860a3316fc6SZhikuiRen { 3861a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 38620fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3863a3316fc6SZhikuiRen std::to_string(skip + top); 3864a3316fc6SZhikuiRen } 3865a3316fc6SZhikuiRen }, 386615124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 386715124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3868a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3869a3316fc6SZhikuiRen bootIndex); 3870a3316fc6SZhikuiRen } 3871a3316fc6SZhikuiRen 38728d1b46d7Szhanghch05 static void 38738d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 38743648c8beSEd Tanous size_t skip, size_t top) 3875a3316fc6SZhikuiRen { 3876a3316fc6SZhikuiRen uint64_t entryCount = 0; 38771e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 38781e1e598dSJonathan Doman *crow::connections::systemBus, 38791e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 38801e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 38811e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 38821e1e598dSJonathan Doman [aResp, entryCount, skip, top](const boost::system::error_code ec, 38831e1e598dSJonathan Doman const uint16_t bootCount) { 3884a3316fc6SZhikuiRen if (ec) 3885a3316fc6SZhikuiRen { 3886a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3887a3316fc6SZhikuiRen messages::internalError(aResp->res); 3888a3316fc6SZhikuiRen return; 3889a3316fc6SZhikuiRen } 38901e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 38911e1e598dSJonathan Doman }); 3892a3316fc6SZhikuiRen } 3893a3316fc6SZhikuiRen 38947e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3895a3316fc6SZhikuiRen { 38967e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 389722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3898ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 38997e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 390045ca1b86SEd Tanous [&app](const crow::Request& req, 390122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 390222d268cbSEd Tanous const std::string& systemName) { 3903c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3904c937d2bfSEd Tanous .canDelegateTop = true, 3905c937d2bfSEd Tanous .canDelegateSkip = true, 3906c937d2bfSEd Tanous }; 3907c937d2bfSEd Tanous query_param::Query delegatedQuery; 3908c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39093ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 391045ca1b86SEd Tanous { 391145ca1b86SEd Tanous return; 391245ca1b86SEd Tanous } 391322d268cbSEd Tanous 391422d268cbSEd Tanous if (systemName != "system") 391522d268cbSEd Tanous { 391622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 391722d268cbSEd Tanous systemName); 391822d268cbSEd Tanous return; 391922d268cbSEd Tanous } 3920a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3921a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3922a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3923a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3924a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3925a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3926a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3927a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3928a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39293648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39305143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39313648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39327e860f15SJohn Edward Broadbent }); 3933a3316fc6SZhikuiRen } 3934a3316fc6SZhikuiRen 3935647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3936647b3cdcSGeorge Liu { 39370fda0f12SGeorge Liu BMCWEB_ROUTE( 39380fda0f12SGeorge Liu app, 393922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3940647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3941647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 394245ca1b86SEd Tanous [&app](const crow::Request& req, 3943647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 394422d268cbSEd Tanous const std::string& systemName, 3945647b3cdcSGeorge Liu const std::string& postCodeID) { 39463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 394745ca1b86SEd Tanous { 394845ca1b86SEd Tanous return; 394945ca1b86SEd Tanous } 395099351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 395199351cd8SEd Tanous req.getHeaderValue("Accept"), 39524a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3953647b3cdcSGeorge Liu { 3954002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3955647b3cdcSGeorge Liu return; 3956647b3cdcSGeorge Liu } 395722d268cbSEd Tanous if (systemName != "system") 395822d268cbSEd Tanous { 395922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 396022d268cbSEd Tanous systemName); 396122d268cbSEd Tanous return; 396222d268cbSEd Tanous } 3963647b3cdcSGeorge Liu 3964647b3cdcSGeorge Liu uint64_t currentValue = 0; 3965647b3cdcSGeorge Liu uint16_t index = 0; 3966647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3967647b3cdcSGeorge Liu { 3968002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3969647b3cdcSGeorge Liu return; 3970647b3cdcSGeorge Liu } 3971647b3cdcSGeorge Liu 3972647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3973647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 3974647b3cdcSGeorge Liu const boost::system::error_code ec, 3975002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 3976002d39b4SEd Tanous postcodes) { 3977647b3cdcSGeorge Liu if (ec.value() == EBADR) 3978647b3cdcSGeorge Liu { 3979002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3980002d39b4SEd Tanous postCodeID); 3981647b3cdcSGeorge Liu return; 3982647b3cdcSGeorge Liu } 3983647b3cdcSGeorge Liu if (ec) 3984647b3cdcSGeorge Liu { 3985647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3986647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 3987647b3cdcSGeorge Liu return; 3988647b3cdcSGeorge Liu } 3989647b3cdcSGeorge Liu 3990647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 3991002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 3992647b3cdcSGeorge Liu { 3993647b3cdcSGeorge Liu BMCWEB_LOG_ERROR << "Wrong currentValue value"; 3994002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3995002d39b4SEd Tanous postCodeID); 3996647b3cdcSGeorge Liu return; 3997647b3cdcSGeorge Liu } 3998647b3cdcSGeorge Liu 39999eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 400046ff87baSEd Tanous if (c.empty()) 4001647b3cdcSGeorge Liu { 4002647b3cdcSGeorge Liu BMCWEB_LOG_INFO << "No found post code data"; 4003002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4004002d39b4SEd Tanous postCodeID); 4005647b3cdcSGeorge Liu return; 4006647b3cdcSGeorge Liu } 400746ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 400846ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 400946ff87baSEd Tanous std::string_view strData(d, c.size()); 4010647b3cdcSGeorge Liu 4011d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4012647b3cdcSGeorge Liu "application/octet-stream"); 4013d9f6c621SEd Tanous asyncResp->res.addHeader( 4014d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4015002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4016647b3cdcSGeorge Liu }, 4017647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4018647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4019002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4020647b3cdcSGeorge Liu }); 4021647b3cdcSGeorge Liu } 4022647b3cdcSGeorge Liu 40237e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4024a3316fc6SZhikuiRen { 40257e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 402622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4027ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40287e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 402945ca1b86SEd Tanous [&app](const crow::Request& req, 40307e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 403122d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40323ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 403345ca1b86SEd Tanous { 403445ca1b86SEd Tanous return; 403545ca1b86SEd Tanous } 403622d268cbSEd Tanous if (systemName != "system") 403722d268cbSEd Tanous { 403822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 403922d268cbSEd Tanous systemName); 404022d268cbSEd Tanous return; 404122d268cbSEd Tanous } 404222d268cbSEd Tanous 40436f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 40447e860f15SJohn Edward Broadbent }); 4045a3316fc6SZhikuiRen } 4046a3316fc6SZhikuiRen 40471da66f75SEd Tanous } // namespace redfish 4048