11da66f75SEd Tanous /* 21da66f75SEd Tanous // Copyright (c) 2018 Intel Corporation 31da66f75SEd Tanous // 41da66f75SEd Tanous // Licensed under the Apache License, Version 2.0 (the "License"); 51da66f75SEd Tanous // you may not use this file except in compliance with the License. 61da66f75SEd Tanous // You may obtain a copy of the License at 71da66f75SEd Tanous // 81da66f75SEd Tanous // http://www.apache.org/licenses/LICENSE-2.0 91da66f75SEd Tanous // 101da66f75SEd Tanous // Unless required by applicable law or agreed to in writing, software 111da66f75SEd Tanous // distributed under the License is distributed on an "AS IS" BASIS, 121da66f75SEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131da66f75SEd Tanous // See the License for the specific language governing permissions and 141da66f75SEd Tanous // limitations under the License. 151da66f75SEd Tanous */ 161da66f75SEd Tanous #pragma once 171da66f75SEd Tanous 18b7028ebfSSpencer Ku #include "gzfile.hpp" 19647b3cdcSGeorge Liu #include "http_utility.hpp" 20b7028ebfSSpencer Ku #include "human_sort.hpp" 214851d45dSJason M. Bills #include "registries.hpp" 224851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 234851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 2446229577SJames Feist #include "task.hpp" 251da66f75SEd Tanous 26e1f26343SJason M. Bills #include <systemd/sd-journal.h> 278e31778eSAsmitha Karunanithi #include <tinyxml2.h> 28400fd1fbSAdriana Kobylak #include <unistd.h> 29e1f26343SJason M. Bills 307e860f15SJohn Edward Broadbent #include <app.hpp> 319896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 3211ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 33400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 344851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 3507c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 361da66f75SEd Tanous #include <boost/container/flat_map.hpp> 371ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 38168e20c1SEd Tanous #include <dbus_utility.hpp> 39cb92c03bSAndrew Geissler #include <error_messages.hpp> 4045ca1b86SEd Tanous #include <query.hpp> 41ed398213SEd Tanous #include <registries/privilege_registry.hpp> 42d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 43d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 44d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp> 452b82937eSEd Tanous #include <utils/time_utils.hpp> 461214b7e7SGunnar Mills 47647b3cdcSGeorge Liu #include <charconv> 484418c7f0SJames Feist #include <filesystem> 4975710de2SXiaochao Ma #include <optional> 5026702d01SEd Tanous #include <span> 51cd225da8SJason M. Bills #include <string_view> 52abf2add6SEd Tanous #include <variant> 531da66f75SEd Tanous 541da66f75SEd Tanous namespace redfish 551da66f75SEd Tanous { 561da66f75SEd Tanous 575b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump"; 585b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump"; 595b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump"; 605b61b5e8SJason M. Bills constexpr char const* deleteAllInterface = 615b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 625b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface = 63424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 646eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface = 656eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 661da66f75SEd Tanous 678e31778eSAsmitha Karunanithi enum class DumpCreationProgress 688e31778eSAsmitha Karunanithi { 698e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 708e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 718e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 728e31778eSAsmitha Karunanithi }; 738e31778eSAsmitha Karunanithi 74fffb8c1fSEd Tanous namespace registries 754851d45dSJason M. Bills { 7626702d01SEd Tanous static const Message* 7726702d01SEd Tanous getMessageFromRegistry(const std::string& messageKey, 7826702d01SEd Tanous const std::span<const MessageEntry> registry) 794851d45dSJason M. Bills { 80002d39b4SEd Tanous std::span<const MessageEntry>::iterator messageIt = 81002d39b4SEd Tanous std::find_if(registry.begin(), registry.end(), 824851d45dSJason M. Bills [&messageKey](const MessageEntry& messageEntry) { 83e662eae8SEd Tanous return std::strcmp(messageEntry.first, messageKey.c_str()) == 0; 844851d45dSJason M. Bills }); 8526702d01SEd Tanous if (messageIt != registry.end()) 864851d45dSJason M. Bills { 874851d45dSJason M. Bills return &messageIt->second; 884851d45dSJason M. Bills } 894851d45dSJason M. Bills 904851d45dSJason M. Bills return nullptr; 914851d45dSJason M. Bills } 924851d45dSJason M. Bills 934851d45dSJason M. Bills static const Message* getMessage(const std::string_view& messageID) 944851d45dSJason M. Bills { 954851d45dSJason M. Bills // Redfish MessageIds are in the form 964851d45dSJason M. Bills // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find 974851d45dSJason M. Bills // the right Message 984851d45dSJason M. Bills std::vector<std::string> fields; 994851d45dSJason M. Bills fields.reserve(4); 1004851d45dSJason M. Bills boost::split(fields, messageID, boost::is_any_of(".")); 10102cad96eSEd Tanous const std::string& registryName = fields[0]; 10202cad96eSEd Tanous const std::string& messageKey = fields[3]; 1034851d45dSJason M. Bills 1044851d45dSJason M. Bills // Find the right registry and check it for the MessageKey 1054851d45dSJason M. Bills if (std::string(base::header.registryPrefix) == registryName) 1064851d45dSJason M. Bills { 1074851d45dSJason M. Bills return getMessageFromRegistry( 10826702d01SEd Tanous messageKey, std::span<const MessageEntry>(base::registry)); 1094851d45dSJason M. Bills } 1104851d45dSJason M. Bills if (std::string(openbmc::header.registryPrefix) == registryName) 1114851d45dSJason M. Bills { 1124851d45dSJason M. Bills return getMessageFromRegistry( 11326702d01SEd Tanous messageKey, std::span<const MessageEntry>(openbmc::registry)); 1144851d45dSJason M. Bills } 1154851d45dSJason M. Bills return nullptr; 1164851d45dSJason M. Bills } 117fffb8c1fSEd Tanous } // namespace registries 1184851d45dSJason M. Bills 119f6150403SJames Feist namespace fs = std::filesystem; 1201da66f75SEd Tanous 121cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 122cb92c03bSAndrew Geissler { 123d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 124d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 125d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 126d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 127cb92c03bSAndrew Geissler { 128cb92c03bSAndrew Geissler return "Critical"; 129cb92c03bSAndrew Geissler } 1303174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 131d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 132d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 133cb92c03bSAndrew Geissler { 134cb92c03bSAndrew Geissler return "OK"; 135cb92c03bSAndrew Geissler } 1363174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 137cb92c03bSAndrew Geissler { 138cb92c03bSAndrew Geissler return "Warning"; 139cb92c03bSAndrew Geissler } 140cb92c03bSAndrew Geissler return ""; 141cb92c03bSAndrew Geissler } 142cb92c03bSAndrew Geissler 143*9017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 144*9017faf2SAbhishek Patel { 145*9017faf2SAbhishek Patel std::optional<bool> notifyAction; 146*9017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 147*9017faf2SAbhishek Patel { 148*9017faf2SAbhishek Patel notifyAction = true; 149*9017faf2SAbhishek Patel } 150*9017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 151*9017faf2SAbhishek Patel { 152*9017faf2SAbhishek Patel notifyAction = false; 153*9017faf2SAbhishek Patel } 154*9017faf2SAbhishek Patel 155*9017faf2SAbhishek Patel return notifyAction; 156*9017faf2SAbhishek Patel } 157*9017faf2SAbhishek Patel 1587e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 15939e77504SEd Tanous const std::string_view& field, 16039e77504SEd Tanous std::string_view& contents) 16116428a1aSJason M. Bills { 16216428a1aSJason M. Bills const char* data = nullptr; 16316428a1aSJason M. Bills size_t length = 0; 16416428a1aSJason M. Bills int ret = 0; 16516428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 16646ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 16746ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 16846ff87baSEd Tanous 16946ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 17016428a1aSJason M. Bills if (ret < 0) 17116428a1aSJason M. Bills { 17216428a1aSJason M. Bills return ret; 17316428a1aSJason M. Bills } 17439e77504SEd Tanous contents = std::string_view(data, length); 17516428a1aSJason M. Bills // Only use the content after the "=" character. 17681ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 17716428a1aSJason M. Bills return ret; 17816428a1aSJason M. Bills } 17916428a1aSJason M. Bills 1807e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 1817e860f15SJohn Edward Broadbent const std::string_view& field, 1827e860f15SJohn Edward Broadbent const int& base, long int& contents) 18316428a1aSJason M. Bills { 18416428a1aSJason M. Bills int ret = 0; 18539e77504SEd Tanous std::string_view metadata; 18616428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 18716428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 18816428a1aSJason M. Bills if (ret < 0) 18916428a1aSJason M. Bills { 19016428a1aSJason M. Bills return ret; 19116428a1aSJason M. Bills } 192b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 19316428a1aSJason M. Bills return ret; 19416428a1aSJason M. Bills } 19516428a1aSJason M. Bills 1967e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1977e860f15SJohn Edward Broadbent std::string& entryTimestamp) 198a3316fc6SZhikuiRen { 199a3316fc6SZhikuiRen int ret = 0; 200a3316fc6SZhikuiRen uint64_t timestamp = 0; 201a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 202a3316fc6SZhikuiRen if (ret < 0) 203a3316fc6SZhikuiRen { 204a3316fc6SZhikuiRen BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 205a3316fc6SZhikuiRen << strerror(-ret); 206a3316fc6SZhikuiRen return false; 207a3316fc6SZhikuiRen } 2082b82937eSEd Tanous entryTimestamp = 2092b82937eSEd Tanous redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000); 2109c620e21SAsmitha Karunanithi return true; 211a3316fc6SZhikuiRen } 21250b8a43aSEd Tanous 2137e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 214e85d6b16SJason M. Bills const bool firstEntry = true) 21516428a1aSJason M. Bills { 21616428a1aSJason M. Bills int ret = 0; 21716428a1aSJason M. Bills static uint64_t prevTs = 0; 21816428a1aSJason M. Bills static int index = 0; 219e85d6b16SJason M. Bills if (firstEntry) 220e85d6b16SJason M. Bills { 221e85d6b16SJason M. Bills prevTs = 0; 222e85d6b16SJason M. Bills } 223e85d6b16SJason M. Bills 22416428a1aSJason M. Bills // Get the entry timestamp 22516428a1aSJason M. Bills uint64_t curTs = 0; 22616428a1aSJason M. Bills ret = sd_journal_get_realtime_usec(journal, &curTs); 22716428a1aSJason M. Bills if (ret < 0) 22816428a1aSJason M. Bills { 22916428a1aSJason M. Bills BMCWEB_LOG_ERROR << "Failed to read entry timestamp: " 23016428a1aSJason M. Bills << strerror(-ret); 23116428a1aSJason M. Bills return false; 23216428a1aSJason M. Bills } 23316428a1aSJason M. Bills // If the timestamp isn't unique, increment the index 23416428a1aSJason M. Bills if (curTs == prevTs) 23516428a1aSJason M. Bills { 23616428a1aSJason M. Bills index++; 23716428a1aSJason M. Bills } 23816428a1aSJason M. Bills else 23916428a1aSJason M. Bills { 24016428a1aSJason M. Bills // Otherwise, reset it 24116428a1aSJason M. Bills index = 0; 24216428a1aSJason M. Bills } 24316428a1aSJason M. Bills // Save the timestamp 24416428a1aSJason M. Bills prevTs = curTs; 24516428a1aSJason M. Bills 24616428a1aSJason M. Bills entryID = std::to_string(curTs); 24716428a1aSJason M. Bills if (index > 0) 24816428a1aSJason M. Bills { 24916428a1aSJason M. Bills entryID += "_" + std::to_string(index); 25016428a1aSJason M. Bills } 25116428a1aSJason M. Bills return true; 25216428a1aSJason M. Bills } 25316428a1aSJason M. Bills 254e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 255e85d6b16SJason M. Bills const bool firstEntry = true) 25695820184SJason M. Bills { 257271584abSEd Tanous static time_t prevTs = 0; 25895820184SJason M. Bills static int index = 0; 259e85d6b16SJason M. Bills if (firstEntry) 260e85d6b16SJason M. Bills { 261e85d6b16SJason M. Bills prevTs = 0; 262e85d6b16SJason M. Bills } 263e85d6b16SJason M. Bills 26495820184SJason M. Bills // Get the entry timestamp 265271584abSEd Tanous std::time_t curTs = 0; 26695820184SJason M. Bills std::tm timeStruct = {}; 26795820184SJason M. Bills std::istringstream entryStream(logEntry); 26895820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 26995820184SJason M. Bills { 27095820184SJason M. Bills curTs = std::mktime(&timeStruct); 27195820184SJason M. Bills } 27295820184SJason M. Bills // If the timestamp isn't unique, increment the index 27395820184SJason M. Bills if (curTs == prevTs) 27495820184SJason M. Bills { 27595820184SJason M. Bills index++; 27695820184SJason M. Bills } 27795820184SJason M. Bills else 27895820184SJason M. Bills { 27995820184SJason M. Bills // Otherwise, reset it 28095820184SJason M. Bills index = 0; 28195820184SJason M. Bills } 28295820184SJason M. Bills // Save the timestamp 28395820184SJason M. Bills prevTs = curTs; 28495820184SJason M. Bills 28595820184SJason M. Bills entryID = std::to_string(curTs); 28695820184SJason M. Bills if (index > 0) 28795820184SJason M. Bills { 28895820184SJason M. Bills entryID += "_" + std::to_string(index); 28995820184SJason M. Bills } 29095820184SJason M. Bills return true; 29195820184SJason M. Bills } 29295820184SJason M. Bills 2937e860f15SJohn Edward Broadbent inline static bool 2948d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2958d1b46d7Szhanghch05 const std::string& entryID, uint64_t& timestamp, 2968d1b46d7Szhanghch05 uint64_t& index) 29716428a1aSJason M. Bills { 29816428a1aSJason M. Bills if (entryID.empty()) 29916428a1aSJason M. Bills { 30016428a1aSJason M. Bills return false; 30116428a1aSJason M. Bills } 30216428a1aSJason M. Bills // Convert the unique ID back to a timestamp to find the entry 30339e77504SEd Tanous std::string_view tsStr(entryID); 30416428a1aSJason M. Bills 30581ce609eSEd Tanous auto underscorePos = tsStr.find('_'); 30671d5d8dbSEd Tanous if (underscorePos != std::string_view::npos) 30716428a1aSJason M. Bills { 30816428a1aSJason M. Bills // Timestamp has an index 30916428a1aSJason M. Bills tsStr.remove_suffix(tsStr.size() - underscorePos); 31039e77504SEd Tanous std::string_view indexStr(entryID); 31116428a1aSJason M. Bills indexStr.remove_prefix(underscorePos + 1); 312c0bd5e4bSEd Tanous auto [ptr, ec] = std::from_chars( 313c0bd5e4bSEd Tanous indexStr.data(), indexStr.data() + indexStr.size(), index); 314c0bd5e4bSEd Tanous if (ec != std::errc()) 31516428a1aSJason M. Bills { 3169db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 31716428a1aSJason M. Bills return false; 31816428a1aSJason M. Bills } 31916428a1aSJason M. Bills } 32016428a1aSJason M. Bills // Timestamp has no index 321c0bd5e4bSEd Tanous auto [ptr, ec] = 322c0bd5e4bSEd Tanous std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp); 323c0bd5e4bSEd Tanous if (ec != std::errc()) 32416428a1aSJason M. Bills { 3259db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 32616428a1aSJason M. Bills return false; 32716428a1aSJason M. Bills } 32816428a1aSJason M. Bills return true; 32916428a1aSJason M. Bills } 33016428a1aSJason M. Bills 33195820184SJason M. Bills static bool 33295820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 33395820184SJason M. Bills { 33495820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 33595820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 33695820184SJason M. Bills 33795820184SJason M. Bills // Loop through the directory looking for redfish log files 33895820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 33995820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 34095820184SJason M. Bills { 34195820184SJason M. Bills // If we find a redfish log file, save the path 34295820184SJason M. Bills std::string filename = dirEnt.path().filename(); 34311ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 34495820184SJason M. Bills { 34595820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 34695820184SJason M. Bills } 34795820184SJason M. Bills } 34895820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 34995820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 35095820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 35195820184SJason M. Bills std::sort(redfishLogFiles.begin(), redfishLogFiles.end()); 35295820184SJason M. Bills 35395820184SJason M. Bills return !redfishLogFiles.empty(); 35495820184SJason M. Bills } 35595820184SJason M. Bills 356aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3572d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 358c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 359aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 360aefe3786SClaire Weinan { 361aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 362aefe3786SClaire Weinan { 363aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 364aefe3786SClaire Weinan { 365aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 366aefe3786SClaire Weinan { 367aefe3786SClaire Weinan if (propertyMap.first == "Status") 368aefe3786SClaire Weinan { 369aefe3786SClaire Weinan const auto* status = 370aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 371aefe3786SClaire Weinan if (status == nullptr) 372aefe3786SClaire Weinan { 373aefe3786SClaire Weinan messages::internalError(asyncResp->res); 374aefe3786SClaire Weinan break; 375aefe3786SClaire Weinan } 376aefe3786SClaire Weinan dumpStatus = *status; 377aefe3786SClaire Weinan } 378aefe3786SClaire Weinan } 379aefe3786SClaire Weinan } 380aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 381aefe3786SClaire Weinan { 382aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 383aefe3786SClaire Weinan { 384aefe3786SClaire Weinan if (propertyMap.first == "Size") 385aefe3786SClaire Weinan { 386aefe3786SClaire Weinan const auto* sizePtr = 387aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 388aefe3786SClaire Weinan if (sizePtr == nullptr) 389aefe3786SClaire Weinan { 390aefe3786SClaire Weinan messages::internalError(asyncResp->res); 391aefe3786SClaire Weinan break; 392aefe3786SClaire Weinan } 393aefe3786SClaire Weinan size = *sizePtr; 394aefe3786SClaire Weinan break; 395aefe3786SClaire Weinan } 396aefe3786SClaire Weinan } 397aefe3786SClaire Weinan } 398aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 399aefe3786SClaire Weinan { 400aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 401aefe3786SClaire Weinan { 402aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 403aefe3786SClaire Weinan { 404aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 405aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 406aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 407aefe3786SClaire Weinan { 408aefe3786SClaire Weinan messages::internalError(asyncResp->res); 409aefe3786SClaire Weinan break; 410aefe3786SClaire Weinan } 411c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 412aefe3786SClaire Weinan break; 413aefe3786SClaire Weinan } 414aefe3786SClaire Weinan } 415aefe3786SClaire Weinan } 416aefe3786SClaire Weinan } 417aefe3786SClaire Weinan } 418aefe3786SClaire Weinan 41921ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 420fdd26906SClaire Weinan { 421fdd26906SClaire Weinan std::string entriesPath; 422fdd26906SClaire Weinan 423fdd26906SClaire Weinan if (dumpType == "BMC") 424fdd26906SClaire Weinan { 425fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 426fdd26906SClaire Weinan } 427fdd26906SClaire Weinan else if (dumpType == "FaultLog") 428fdd26906SClaire Weinan { 429fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 430fdd26906SClaire Weinan } 431fdd26906SClaire Weinan else if (dumpType == "System") 432fdd26906SClaire Weinan { 433fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 434fdd26906SClaire Weinan } 435fdd26906SClaire Weinan else 436fdd26906SClaire Weinan { 437fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: " 438fdd26906SClaire Weinan << dumpType; 439fdd26906SClaire Weinan } 440fdd26906SClaire Weinan 441fdd26906SClaire Weinan // Returns empty string on error 442fdd26906SClaire Weinan return entriesPath; 443fdd26906SClaire Weinan } 444fdd26906SClaire Weinan 4458d1b46d7Szhanghch05 inline void 4468d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4475cb1dd27SAsmitha Karunanithi const std::string& dumpType) 4485cb1dd27SAsmitha Karunanithi { 449fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 450fdd26906SClaire Weinan if (entriesPath.empty()) 4515cb1dd27SAsmitha Karunanithi { 4525cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4535cb1dd27SAsmitha Karunanithi return; 4545cb1dd27SAsmitha Karunanithi } 4555cb1dd27SAsmitha Karunanithi 4565cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 457fdd26906SClaire Weinan [asyncResp, entriesPath, 458711ac7a9SEd Tanous dumpType](const boost::system::error_code ec, 459711ac7a9SEd Tanous dbus::utility::ManagedObjectType& resp) { 4605cb1dd27SAsmitha Karunanithi if (ec) 4615cb1dd27SAsmitha Karunanithi { 4625cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 4635cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 4645cb1dd27SAsmitha Karunanithi return; 4655cb1dd27SAsmitha Karunanithi } 4665cb1dd27SAsmitha Karunanithi 467fdd26906SClaire Weinan // Remove ending slash 468fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 469fdd26906SClaire Weinan if (!odataIdStr.empty()) 470fdd26906SClaire Weinan { 471fdd26906SClaire Weinan odataIdStr.pop_back(); 472fdd26906SClaire Weinan } 473fdd26906SClaire Weinan 474fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 475fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 476fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 477fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 478fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = 479fdd26906SClaire Weinan "Collection of " + dumpType + " Dump Entries"; 480fdd26906SClaire Weinan 4815cb1dd27SAsmitha Karunanithi nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 4825cb1dd27SAsmitha Karunanithi entriesArray = nlohmann::json::array(); 483b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 484b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 485002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 4865cb1dd27SAsmitha Karunanithi 487002d39b4SEd Tanous std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) { 488002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 489002d39b4SEd Tanous r.first.filename()); 490565dfb6fSClaire Weinan }); 491565dfb6fSClaire Weinan 4925cb1dd27SAsmitha Karunanithi for (auto& object : resp) 4935cb1dd27SAsmitha Karunanithi { 494b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 4955cb1dd27SAsmitha Karunanithi { 4965cb1dd27SAsmitha Karunanithi continue; 4975cb1dd27SAsmitha Karunanithi } 498c6fecdabSClaire Weinan uint64_t timestampUs = 0; 4995cb1dd27SAsmitha Karunanithi uint64_t size = 0; 50035440d18SAsmitha Karunanithi std::string dumpStatus; 501433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5022dfd18efSEd Tanous 5032dfd18efSEd Tanous std::string entryID = object.first.filename(); 5042dfd18efSEd Tanous if (entryID.empty()) 5055cb1dd27SAsmitha Karunanithi { 5065cb1dd27SAsmitha Karunanithi continue; 5075cb1dd27SAsmitha Karunanithi } 5085cb1dd27SAsmitha Karunanithi 509c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 510aefe3786SClaire Weinan asyncResp); 5115cb1dd27SAsmitha Karunanithi 5120fda0f12SGeorge Liu if (dumpStatus != 5130fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 51435440d18SAsmitha Karunanithi !dumpStatus.empty()) 51535440d18SAsmitha Karunanithi { 51635440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 51735440d18SAsmitha Karunanithi continue; 51835440d18SAsmitha Karunanithi } 51935440d18SAsmitha Karunanithi 5209c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 521fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5225cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5235cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5245cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 525bbd80db8SClaire Weinan thisEntry["Created"] = 526bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5275cb1dd27SAsmitha Karunanithi 5285cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5295cb1dd27SAsmitha Karunanithi { 530d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 531d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 532fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 533fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5345cb1dd27SAsmitha Karunanithi } 5355cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 5365cb1dd27SAsmitha Karunanithi { 537d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 538d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 539d337bb72SAsmitha Karunanithi thisEntry["AdditionalDataURI"] = 540fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 541fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 5425cb1dd27SAsmitha Karunanithi } 54335440d18SAsmitha Karunanithi entriesArray.push_back(std::move(thisEntry)); 5445cb1dd27SAsmitha Karunanithi } 545002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 5465cb1dd27SAsmitha Karunanithi }, 5475cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 5485cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 5495cb1dd27SAsmitha Karunanithi } 5505cb1dd27SAsmitha Karunanithi 5518d1b46d7Szhanghch05 inline void 552c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5538d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 5545cb1dd27SAsmitha Karunanithi { 555fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 556fdd26906SClaire Weinan if (entriesPath.empty()) 5575cb1dd27SAsmitha Karunanithi { 5585cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5595cb1dd27SAsmitha Karunanithi return; 5605cb1dd27SAsmitha Karunanithi } 5615cb1dd27SAsmitha Karunanithi 5625cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 563fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 564fdd26906SClaire Weinan entriesPath](const boost::system::error_code ec, 56502cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 5665cb1dd27SAsmitha Karunanithi if (ec) 5675cb1dd27SAsmitha Karunanithi { 5685cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec; 5695cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5705cb1dd27SAsmitha Karunanithi return; 5715cb1dd27SAsmitha Karunanithi } 5725cb1dd27SAsmitha Karunanithi 573b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 574b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 575b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 576002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 577b47452b2SAsmitha Karunanithi 5789eb808c1SEd Tanous for (const auto& objectPath : resp) 5795cb1dd27SAsmitha Karunanithi { 580b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 5815cb1dd27SAsmitha Karunanithi { 5825cb1dd27SAsmitha Karunanithi continue; 5835cb1dd27SAsmitha Karunanithi } 5845cb1dd27SAsmitha Karunanithi 5855cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 586c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5875cb1dd27SAsmitha Karunanithi uint64_t size = 0; 58835440d18SAsmitha Karunanithi std::string dumpStatus; 5895cb1dd27SAsmitha Karunanithi 590aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 591c6fecdabSClaire Weinan timestampUs, asyncResp); 5925cb1dd27SAsmitha Karunanithi 5930fda0f12SGeorge Liu if (dumpStatus != 5940fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 59535440d18SAsmitha Karunanithi !dumpStatus.empty()) 59635440d18SAsmitha Karunanithi { 59735440d18SAsmitha Karunanithi // Dump status is not Complete 59835440d18SAsmitha Karunanithi // return not found until status is changed to Completed 599d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 600d1bde9e5SKrzysztof Grobelny entryID); 60135440d18SAsmitha Karunanithi return; 60235440d18SAsmitha Karunanithi } 60335440d18SAsmitha Karunanithi 6045cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 6059c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 606fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6075cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6085cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6095cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 610bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 611bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6125cb1dd27SAsmitha Karunanithi 6135cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6145cb1dd27SAsmitha Karunanithi { 615d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 616d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 617fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 618fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6195cb1dd27SAsmitha Karunanithi } 6205cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6215cb1dd27SAsmitha Karunanithi { 622d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 623002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 624d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 625fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 626fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6275cb1dd27SAsmitha Karunanithi } 6285cb1dd27SAsmitha Karunanithi } 629e05aec50SEd Tanous if (!foundDumpEntry) 630b47452b2SAsmitha Karunanithi { 631b47452b2SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Can't find Dump Entry"; 632b47452b2SAsmitha Karunanithi messages::internalError(asyncResp->res); 633b47452b2SAsmitha Karunanithi return; 634b47452b2SAsmitha Karunanithi } 6355cb1dd27SAsmitha Karunanithi }, 6365cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", 6375cb1dd27SAsmitha Karunanithi "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6385cb1dd27SAsmitha Karunanithi } 6395cb1dd27SAsmitha Karunanithi 6408d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6419878256fSStanley Chu const std::string& entryID, 642b47452b2SAsmitha Karunanithi const std::string& dumpType) 6435cb1dd27SAsmitha Karunanithi { 644002d39b4SEd Tanous auto respHandler = 645002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 6465cb1dd27SAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done"; 6475cb1dd27SAsmitha Karunanithi if (ec) 6485cb1dd27SAsmitha Karunanithi { 6493de8d8baSGeorge Liu if (ec.value() == EBADR) 6503de8d8baSGeorge Liu { 6513de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 6523de8d8baSGeorge Liu return; 6533de8d8baSGeorge Liu } 6545cb1dd27SAsmitha Karunanithi BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error " 655fdd26906SClaire Weinan << ec << " entryID=" << entryID; 6565cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6575cb1dd27SAsmitha Karunanithi return; 6585cb1dd27SAsmitha Karunanithi } 6595cb1dd27SAsmitha Karunanithi }; 6605cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 6615cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 662b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 663b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 664b47452b2SAsmitha Karunanithi entryID, 6655cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 6665cb1dd27SAsmitha Karunanithi } 6675cb1dd27SAsmitha Karunanithi 6688e31778eSAsmitha Karunanithi inline DumpCreationProgress 6698e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 670a43be80fSAsmitha Karunanithi { 6718e31778eSAsmitha Karunanithi if (status == 6728e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 6738e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 6748e31778eSAsmitha Karunanithi { 6758e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6768e31778eSAsmitha Karunanithi } 6778e31778eSAsmitha Karunanithi if (status == 6788e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 6798e31778eSAsmitha Karunanithi { 6808e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 6818e31778eSAsmitha Karunanithi } 6828e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 6838e31778eSAsmitha Karunanithi } 6848e31778eSAsmitha Karunanithi 6858e31778eSAsmitha Karunanithi inline DumpCreationProgress 6868e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 6878e31778eSAsmitha Karunanithi { 6888e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 6898e31778eSAsmitha Karunanithi { 6908e31778eSAsmitha Karunanithi if (key == "Status") 6918e31778eSAsmitha Karunanithi { 6928e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 6938e31778eSAsmitha Karunanithi if (value == nullptr) 6948e31778eSAsmitha Karunanithi { 6958e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Status property value is null"; 6968e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 6978e31778eSAsmitha Karunanithi } 6988e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 6998e31778eSAsmitha Karunanithi } 7008e31778eSAsmitha Karunanithi } 7018e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 7028e31778eSAsmitha Karunanithi } 7038e31778eSAsmitha Karunanithi 7048e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 7058e31778eSAsmitha Karunanithi { 7068e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 7078e31778eSAsmitha Karunanithi { 7088e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 7098e31778eSAsmitha Karunanithi } 7108e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 7118e31778eSAsmitha Karunanithi { 7128e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 7138e31778eSAsmitha Karunanithi } 7148e31778eSAsmitha Karunanithi return ""; 7158e31778eSAsmitha Karunanithi } 7168e31778eSAsmitha Karunanithi 7178e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 7188e31778eSAsmitha Karunanithi task::Payload&& payload, 7198e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7208e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 7218e31778eSAsmitha Karunanithi { 7228e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 7238e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 7248e31778eSAsmitha Karunanithi 7258e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 7268e31778eSAsmitha Karunanithi 7278e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 7288e31778eSAsmitha Karunanithi { 7298e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Invalid dump type received"; 7308e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7318e31778eSAsmitha Karunanithi return; 7328e31778eSAsmitha Karunanithi } 7338e31778eSAsmitha Karunanithi 7348e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7358e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 7368e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 7378e31778eSAsmitha Karunanithi dumpId](const boost::system::error_code ec, 7388e31778eSAsmitha Karunanithi const std::string& introspectXml) { 7398e31778eSAsmitha Karunanithi if (ec) 7408e31778eSAsmitha Karunanithi { 7418e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Introspect call failed with error: " 7428e31778eSAsmitha Karunanithi << ec.message(); 7438e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7448e31778eSAsmitha Karunanithi return; 7458e31778eSAsmitha Karunanithi } 7468e31778eSAsmitha Karunanithi 7478e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 7488e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 7498e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 7508e31778eSAsmitha Karunanithi // Else, return task completed. 7518e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 7528e31778eSAsmitha Karunanithi 7538e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 7548e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 7558e31778eSAsmitha Karunanithi if (pRoot == nullptr) 7568e31778eSAsmitha Karunanithi { 7578e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << "XML document failed to parse"; 7588e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 7598e31778eSAsmitha Karunanithi return; 7608e31778eSAsmitha Karunanithi } 7618e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 7628e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 7638e31778eSAsmitha Karunanithi 7648e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 7658e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 7668e31778eSAsmitha Karunanithi { 7678e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 7688e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 7698e31778eSAsmitha Karunanithi { 7708e31778eSAsmitha Karunanithi if (thisInterfaceName == 7718e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 7728e31778eSAsmitha Karunanithi { 7738e31778eSAsmitha Karunanithi interfaceNode = 7748e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 7758e31778eSAsmitha Karunanithi continue; 7768e31778eSAsmitha Karunanithi } 7778e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 7788e31778eSAsmitha Karunanithi break; 7798e31778eSAsmitha Karunanithi } 7808e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 7818e31778eSAsmitha Karunanithi } 7828e31778eSAsmitha Karunanithi 783a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 7848e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 7855b378546SPatrick Williams boost::system::error_code err, sdbusplus::message_t& msg, 786a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 787cb13a392SEd Tanous if (err) 788cb13a392SEd Tanous { 7898e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 7908e31778eSAsmitha Karunanithi << ": Error in creating dump"; 7918e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 7926145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 7936145ed6fSAsmitha Karunanithi return task::completed; 794cb13a392SEd Tanous } 795b9d36b47SEd Tanous 7968e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 797a43be80fSAsmitha Karunanithi { 7988e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 7998e31778eSAsmitha Karunanithi std::string prop; 8008e31778eSAsmitha Karunanithi msg.read(prop, values); 8018e31778eSAsmitha Karunanithi 8028e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 8038e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 8048e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 8058e31778eSAsmitha Karunanithi { 8068e31778eSAsmitha Karunanithi BMCWEB_LOG_ERROR << createdObjPath.str 8078e31778eSAsmitha Karunanithi << ": Error in creating dump"; 8088e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 8098e31778eSAsmitha Karunanithi return task::completed; 8108e31778eSAsmitha Karunanithi } 8118e31778eSAsmitha Karunanithi 8128e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 8138e31778eSAsmitha Karunanithi { 8148e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8158e31778eSAsmitha Karunanithi << ": Dump creation task is in progress"; 8168e31778eSAsmitha Karunanithi return !task::completed; 8178e31778eSAsmitha Karunanithi } 8188e31778eSAsmitha Karunanithi } 8198e31778eSAsmitha Karunanithi 820a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 821a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 822a43be80fSAsmitha Karunanithi 823a43be80fSAsmitha Karunanithi std::string headerLoc = 8248e31778eSAsmitha Karunanithi "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId); 825002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 826a43be80fSAsmitha Karunanithi 8278e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << createdObjPath.str 8288e31778eSAsmitha Karunanithi << ": Dump creation task completed"; 829a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 830b47452b2SAsmitha Karunanithi return task::completed; 831a43be80fSAsmitha Karunanithi }, 8328e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 8338e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 8348e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 835a43be80fSAsmitha Karunanithi 8368e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 8378e31778eSAsmitha Karunanithi // requested dump will be collected. 8388e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 839a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 8408e31778eSAsmitha Karunanithi task->payload.emplace(payload); 8418e31778eSAsmitha Karunanithi }, 8428e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 8438e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 844a43be80fSAsmitha Karunanithi } 845a43be80fSAsmitha Karunanithi 8468d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8478d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 848a43be80fSAsmitha Karunanithi { 849fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 850fdd26906SClaire Weinan if (dumpPath.empty()) 851a43be80fSAsmitha Karunanithi { 852a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 853a43be80fSAsmitha Karunanithi return; 854a43be80fSAsmitha Karunanithi } 855a43be80fSAsmitha Karunanithi 856a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 857a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 858a43be80fSAsmitha Karunanithi 85915ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 860a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 861a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 862a43be80fSAsmitha Karunanithi { 863a43be80fSAsmitha Karunanithi return; 864a43be80fSAsmitha Karunanithi } 865a43be80fSAsmitha Karunanithi 866a43be80fSAsmitha Karunanithi if (dumpType == "System") 867a43be80fSAsmitha Karunanithi { 868a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 869a43be80fSAsmitha Karunanithi { 8704978b63fSJason M. Bills BMCWEB_LOG_ERROR 8714978b63fSJason M. Bills << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"; 872a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 873a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 874a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 875a43be80fSAsmitha Karunanithi return; 876a43be80fSAsmitha Karunanithi } 8773174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 878a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 879a43be80fSAsmitha Karunanithi { 880a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "Wrong parameter values passed"; 881ace85d60SEd Tanous messages::internalError(asyncResp->res); 882a43be80fSAsmitha Karunanithi return; 883a43be80fSAsmitha Karunanithi } 8845907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 885a43be80fSAsmitha Karunanithi } 886a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 887a43be80fSAsmitha Karunanithi { 888a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 889a43be80fSAsmitha Karunanithi { 8900fda0f12SGeorge Liu BMCWEB_LOG_ERROR 8910fda0f12SGeorge Liu << "CreateDump action parameter 'DiagnosticDataType' not found!"; 892a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 893a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 894a43be80fSAsmitha Karunanithi return; 895a43be80fSAsmitha Karunanithi } 8963174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 897a43be80fSAsmitha Karunanithi { 898a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR 899a43be80fSAsmitha Karunanithi << "Wrong parameter value passed for 'DiagnosticDataType'"; 900ace85d60SEd Tanous messages::internalError(asyncResp->res); 901a43be80fSAsmitha Karunanithi return; 902a43be80fSAsmitha Karunanithi } 9035907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 9045907571dSAsmitha Karunanithi } 9055907571dSAsmitha Karunanithi else 9065907571dSAsmitha Karunanithi { 9075907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type"; 9085907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9095907571dSAsmitha Karunanithi return; 910a43be80fSAsmitha Karunanithi } 911a43be80fSAsmitha Karunanithi 9128e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 9138e31778eSAsmitha Karunanithi createDumpParamVec; 9148e31778eSAsmitha Karunanithi 915a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9165b378546SPatrick Williams [asyncResp, payload(task::Payload(req)), dumpPath]( 9175b378546SPatrick Williams const boost::system::error_code ec, const sdbusplus::message_t& msg, 9188e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 919a43be80fSAsmitha Karunanithi if (ec) 920a43be80fSAsmitha Karunanithi { 921a43be80fSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec; 9225907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 9235907571dSAsmitha Karunanithi if (dbusError == nullptr) 9245907571dSAsmitha Karunanithi { 9255907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 9265907571dSAsmitha Karunanithi return; 9275907571dSAsmitha Karunanithi } 9285907571dSAsmitha Karunanithi 9295907571dSAsmitha Karunanithi BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name 9305907571dSAsmitha Karunanithi << " and error msg: " << dbusError->message; 9315907571dSAsmitha Karunanithi if (std::string_view( 9325907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 9335907571dSAsmitha Karunanithi dbusError->name) 9345907571dSAsmitha Karunanithi { 9355907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 9365907571dSAsmitha Karunanithi return; 9375907571dSAsmitha Karunanithi } 9385907571dSAsmitha Karunanithi if (std::string_view( 9395907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 9405907571dSAsmitha Karunanithi dbusError->name) 9415907571dSAsmitha Karunanithi { 9425907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 9435907571dSAsmitha Karunanithi return; 9445907571dSAsmitha Karunanithi } 9455907571dSAsmitha Karunanithi if (std::string_view( 9465907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 9475907571dSAsmitha Karunanithi dbusError->name) 9485907571dSAsmitha Karunanithi { 9495907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 9505907571dSAsmitha Karunanithi return; 9515907571dSAsmitha Karunanithi } 9525907571dSAsmitha Karunanithi // Other Dbus errors such as: 9535907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 9545907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 9555907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 9565907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 9575907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 9585907571dSAsmitha Karunanithi // back to the client. 959a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 960a43be80fSAsmitha Karunanithi return; 961a43be80fSAsmitha Karunanithi } 9628e31778eSAsmitha Karunanithi BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str; 9638e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 964a43be80fSAsmitha Karunanithi }, 965b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 966b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 967b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 9688e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 969a43be80fSAsmitha Karunanithi } 970a43be80fSAsmitha Karunanithi 9718d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9728d1b46d7Szhanghch05 const std::string& dumpType) 97380319af1SAsmitha Karunanithi { 974b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 975b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 9768d1b46d7Szhanghch05 97780319af1SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 978b9d36b47SEd Tanous [asyncResp, dumpType]( 979b9d36b47SEd Tanous const boost::system::error_code ec, 980b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 98180319af1SAsmitha Karunanithi if (ec) 98280319af1SAsmitha Karunanithi { 98380319af1SAsmitha Karunanithi BMCWEB_LOG_ERROR << "resp_handler got error " << ec; 98480319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 98580319af1SAsmitha Karunanithi return; 98680319af1SAsmitha Karunanithi } 98780319af1SAsmitha Karunanithi 98880319af1SAsmitha Karunanithi for (const std::string& path : subTreePaths) 98980319af1SAsmitha Karunanithi { 9902dfd18efSEd Tanous sdbusplus::message::object_path objPath(path); 9912dfd18efSEd Tanous std::string logID = objPath.filename(); 9922dfd18efSEd Tanous if (logID.empty()) 99380319af1SAsmitha Karunanithi { 9942dfd18efSEd Tanous continue; 99580319af1SAsmitha Karunanithi } 9962dfd18efSEd Tanous deleteDumpEntry(asyncResp, logID, dumpType); 99780319af1SAsmitha Karunanithi } 99880319af1SAsmitha Karunanithi }, 99980319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", 100080319af1SAsmitha Karunanithi "/xyz/openbmc_project/object_mapper", 100180319af1SAsmitha Karunanithi "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 1002b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, 1003b47452b2SAsmitha Karunanithi std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." + 1004b47452b2SAsmitha Karunanithi dumpType}); 100580319af1SAsmitha Karunanithi } 100680319af1SAsmitha Karunanithi 1007b9d36b47SEd Tanous inline static void 1008b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1009b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1010b9d36b47SEd Tanous std::string& logfile) 1011043a0536SJohnathan Mantey { 1012d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1013d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1014d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1015d1bde9e5SKrzysztof Grobelny 1016d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1017d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1018d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1019d1bde9e5SKrzysztof Grobelny 1020d1bde9e5SKrzysztof Grobelny if (!success) 1021043a0536SJohnathan Mantey { 1022d1bde9e5SKrzysztof Grobelny return; 1023043a0536SJohnathan Mantey } 1024d1bde9e5SKrzysztof Grobelny 1025d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1026043a0536SJohnathan Mantey { 1027d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1028d1bde9e5SKrzysztof Grobelny } 1029d1bde9e5SKrzysztof Grobelny 1030d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1031043a0536SJohnathan Mantey { 1032d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1033043a0536SJohnathan Mantey } 1034d1bde9e5SKrzysztof Grobelny 1035d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1036043a0536SJohnathan Mantey { 1037d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1038043a0536SJohnathan Mantey } 1039043a0536SJohnathan Mantey } 1040043a0536SJohnathan Mantey 1041a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode"; 10427e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 10431da66f75SEd Tanous { 1044c4bf6374SJason M. Bills /** 1045c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1046c4bf6374SJason M. Bills */ 104722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1048ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1049002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1050002d39b4SEd Tanous [&app](const crow::Request& req, 105122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 105222d268cbSEd Tanous const std::string& systemName) { 10533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1054c4bf6374SJason M. Bills { 105545ca1b86SEd Tanous return; 105645ca1b86SEd Tanous } 105722d268cbSEd Tanous if (systemName != "system") 105822d268cbSEd Tanous { 105922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 106022d268cbSEd Tanous systemName); 106122d268cbSEd Tanous return; 106222d268cbSEd Tanous } 106322d268cbSEd Tanous 10647e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 10657e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1066c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1067c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1068c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1069029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 107045ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1071c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1072c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1073002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1074c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 10751476687dSEd Tanous nlohmann::json::object_t eventLog; 10761476687dSEd Tanous eventLog["@odata.id"] = 10771476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 10781476687dSEd Tanous logServiceArray.push_back(std::move(eventLog)); 10795cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 10801476687dSEd Tanous nlohmann::json::object_t dumpLog; 1081002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 10821476687dSEd Tanous logServiceArray.push_back(std::move(dumpLog)); 1083c9bb6861Sraviteja-b #endif 1084c9bb6861Sraviteja-b 1085d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 10861476687dSEd Tanous nlohmann::json::object_t crashdump; 10871476687dSEd Tanous crashdump["@odata.id"] = 10881476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 10891476687dSEd Tanous logServiceArray.push_back(std::move(crashdump)); 1090d53dd41fSJason M. Bills #endif 1091b7028ebfSSpencer Ku 1092b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 10931476687dSEd Tanous nlohmann::json::object_t hostlogger; 10941476687dSEd Tanous hostlogger["@odata.id"] = 10951476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 10961476687dSEd Tanous logServiceArray.push_back(std::move(hostlogger)); 1097b7028ebfSSpencer Ku #endif 1098c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1099c4bf6374SJason M. Bills logServiceArray.size(); 1100a3316fc6SZhikuiRen 1101a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 110245ca1b86SEd Tanous [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 } 1128a3316fc6SZhikuiRen }, 1129a3316fc6SZhikuiRen "xyz.openbmc_project.ObjectMapper", 1130a3316fc6SZhikuiRen "/xyz/openbmc_project/object_mapper", 113145ca1b86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0, 113245ca1b86SEd Tanous std::array<const char*, 1>{postCodeIface}); 11337e860f15SJohn Edward Broadbent }); 1134c4bf6374SJason M. Bills } 1135c4bf6374SJason M. Bills 11367e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1137c4bf6374SJason M. Bills { 113822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1139ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1140002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1141002d39b4SEd Tanous [&app](const crow::Request& req, 114222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 114322d268cbSEd Tanous const std::string& systemName) { 11443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114545ca1b86SEd Tanous { 114645ca1b86SEd Tanous return; 114745ca1b86SEd Tanous } 114822d268cbSEd Tanous if (systemName != "system") 114922d268cbSEd Tanous { 115022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 115122d268cbSEd Tanous systemName); 115222d268cbSEd Tanous return; 115322d268cbSEd Tanous } 1154c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1155029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1156c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1157c4bf6374SJason M. Bills "#LogService.v1_1_0.LogService"; 1158c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1159002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1160c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1161c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 11627c8c4058STejas Patil 11637c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 11642b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 11657c8c4058STejas Patil 11667c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 11677c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 11687c8c4058STejas Patil redfishDateTimeOffset.second; 11697c8c4058STejas Patil 11701476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 11711476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1172e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1173e7d6c8b2SGunnar Mills 11740fda0f12SGeorge Liu {"target", 11750fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 11767e860f15SJohn Edward Broadbent }); 1177489640c6SJason M. Bills } 1178489640c6SJason M. Bills 11797e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1180489640c6SJason M. Bills { 11814978b63fSJason M. Bills BMCWEB_ROUTE( 11824978b63fSJason M. Bills app, 118322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1184432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 11857e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 118645ca1b86SEd Tanous [&app](const crow::Request& req, 118722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 118822d268cbSEd Tanous const std::string& systemName) { 11893ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 119045ca1b86SEd Tanous { 119145ca1b86SEd Tanous return; 119245ca1b86SEd Tanous } 119322d268cbSEd Tanous if (systemName != "system") 119422d268cbSEd Tanous { 119522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 119622d268cbSEd Tanous systemName); 119722d268cbSEd Tanous return; 119822d268cbSEd Tanous } 1199489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1200489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1201489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1202489640c6SJason M. Bills { 1203489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1204489640c6SJason M. Bills { 1205489640c6SJason M. Bills std::error_code ec; 1206489640c6SJason M. Bills std::filesystem::remove(file, ec); 1207489640c6SJason M. Bills } 1208489640c6SJason M. Bills } 1209489640c6SJason M. Bills 1210489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1211489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 1212489640c6SJason M. Bills [asyncResp](const boost::system::error_code ec) { 1213489640c6SJason M. Bills if (ec) 1214489640c6SJason M. Bills { 1215002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec; 1216489640c6SJason M. Bills messages::internalError(asyncResp->res); 1217489640c6SJason M. Bills return; 1218489640c6SJason M. Bills } 1219489640c6SJason M. Bills 1220489640c6SJason M. Bills messages::success(asyncResp->res); 1221489640c6SJason M. Bills }, 1222489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1223002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1224002d39b4SEd Tanous "replace"); 12257e860f15SJohn Edward Broadbent }); 1226c4bf6374SJason M. Bills } 1227c4bf6374SJason M. Bills 1228ac992cdeSJason M. Bills enum class LogParseError 1229ac992cdeSJason M. Bills { 1230ac992cdeSJason M. Bills success, 1231ac992cdeSJason M. Bills parseFailed, 1232ac992cdeSJason M. Bills messageIdNotInRegistry, 1233ac992cdeSJason M. Bills }; 1234ac992cdeSJason M. Bills 1235ac992cdeSJason M. Bills static LogParseError 1236ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1237b5a76932SEd Tanous const std::string& logEntry, 1238de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1239c4bf6374SJason M. Bills { 124095820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1241cd225da8SJason M. Bills // First get the Timestamp 1242f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1243cd225da8SJason M. Bills if (space == std::string::npos) 124495820184SJason M. Bills { 1245ac992cdeSJason M. Bills return LogParseError::parseFailed; 124695820184SJason M. Bills } 1247cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1248cd225da8SJason M. Bills // Then get the log contents 1249f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1250cd225da8SJason M. Bills if (entryStart == std::string::npos) 1251cd225da8SJason M. Bills { 1252ac992cdeSJason M. Bills return LogParseError::parseFailed; 1253cd225da8SJason M. Bills } 1254cd225da8SJason M. Bills std::string_view entry(logEntry); 1255cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1256cd225da8SJason M. Bills // Use split to separate the entry into its fields 1257cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 1258cd225da8SJason M. Bills boost::split(logEntryFields, entry, boost::is_any_of(","), 1259cd225da8SJason M. Bills boost::token_compress_on); 1260cd225da8SJason M. Bills // We need at least a MessageId to be valid 126126f6976fSEd Tanous if (logEntryFields.empty()) 1262cd225da8SJason M. Bills { 1263ac992cdeSJason M. Bills return LogParseError::parseFailed; 1264cd225da8SJason M. Bills } 1265cd225da8SJason M. Bills std::string& messageID = logEntryFields[0]; 126695820184SJason M. Bills 12674851d45dSJason M. Bills // Get the Message from the MessageRegistry 1268fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1269c4bf6374SJason M. Bills 127054417b02SSui Chen if (message == nullptr) 1271c4bf6374SJason M. Bills { 127254417b02SSui Chen BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry; 1273ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1274c4bf6374SJason M. Bills } 1275c4bf6374SJason M. Bills 127654417b02SSui Chen std::string msg = message->message; 127754417b02SSui Chen 127815a86ff6SJason M. Bills // Get the MessageArgs from the log if there are any 127926702d01SEd Tanous std::span<std::string> messageArgs; 128015a86ff6SJason M. Bills if (logEntryFields.size() > 1) 128115a86ff6SJason M. Bills { 128215a86ff6SJason M. Bills std::string& messageArgsStart = logEntryFields[1]; 128315a86ff6SJason M. Bills // If the first string is empty, assume there are no MessageArgs 128415a86ff6SJason M. Bills std::size_t messageArgsSize = 0; 128515a86ff6SJason M. Bills if (!messageArgsStart.empty()) 128615a86ff6SJason M. Bills { 128715a86ff6SJason M. Bills messageArgsSize = logEntryFields.size() - 1; 128815a86ff6SJason M. Bills } 128915a86ff6SJason M. Bills 129023a21a1cSEd Tanous messageArgs = {&messageArgsStart, messageArgsSize}; 1291c4bf6374SJason M. Bills 12924851d45dSJason M. Bills // Fill the MessageArgs into the Message 129395820184SJason M. Bills int i = 0; 129495820184SJason M. Bills for (const std::string& messageArg : messageArgs) 12954851d45dSJason M. Bills { 129695820184SJason M. Bills std::string argStr = "%" + std::to_string(++i); 12974851d45dSJason M. Bills size_t argPos = msg.find(argStr); 12984851d45dSJason M. Bills if (argPos != std::string::npos) 12994851d45dSJason M. Bills { 130095820184SJason M. Bills msg.replace(argPos, argStr.length(), messageArg); 13014851d45dSJason M. Bills } 13024851d45dSJason M. Bills } 130315a86ff6SJason M. Bills } 13044851d45dSJason M. Bills 130595820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 130695820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 130795820184SJason M. Bills // between the '.' and the '+', so just remove them. 1308f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1309f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 131095820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1311c4bf6374SJason M. Bills { 131295820184SJason M. Bills timestamp.erase(dot, plus - dot); 1313c4bf6374SJason M. Bills } 1314c4bf6374SJason M. Bills 1315c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 13169c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 131784afc48bSJason M. Bills logEntryJson["@odata.id"] = 131884afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID; 131984afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 132084afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 132184afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 132284afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 132384afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 132484afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 132584afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 132684afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1327ac992cdeSJason M. Bills return LogParseError::success; 1328c4bf6374SJason M. Bills } 1329c4bf6374SJason M. Bills 13307e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1331c4bf6374SJason M. Bills { 133222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 13338b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1334002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1335002d39b4SEd Tanous [&app](const crow::Request& req, 133622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 133722d268cbSEd Tanous const std::string& systemName) { 1338c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1339c937d2bfSEd Tanous .canDelegateTop = true, 1340c937d2bfSEd Tanous .canDelegateSkip = true, 1341c937d2bfSEd Tanous }; 1342c937d2bfSEd Tanous query_param::Query delegatedQuery; 1343c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 13443ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1345c4bf6374SJason M. Bills { 1346c4bf6374SJason M. Bills return; 1347c4bf6374SJason M. Bills } 134822d268cbSEd Tanous if (systemName != "system") 134922d268cbSEd Tanous { 135022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 135122d268cbSEd Tanous systemName); 135222d268cbSEd Tanous return; 135322d268cbSEd Tanous } 135422d268cbSEd Tanous 13555143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 13563648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 13573648c8beSEd Tanous 13587e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13597e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1360c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1361c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1362c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1363029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1364c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1365c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1366c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1367cb92c03bSAndrew Geissler 13684978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1369c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 13707e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 13717e860f15SJohn Edward Broadbent // entry 137295820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 137395820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1374b01bf299SEd Tanous uint64_t entryCount = 0; 1375cd225da8SJason M. Bills std::string logEntry; 137695820184SJason M. Bills 13777e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 13787e860f15SJohn Edward Broadbent // backwards 1379002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1380002d39b4SEd Tanous it++) 1381c4bf6374SJason M. Bills { 1382cd225da8SJason M. Bills std::ifstream logStream(*it); 138395820184SJason M. Bills if (!logStream.is_open()) 1384c4bf6374SJason M. Bills { 1385c4bf6374SJason M. Bills continue; 1386c4bf6374SJason M. Bills } 1387c4bf6374SJason M. Bills 1388e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1389e85d6b16SJason M. Bills bool firstEntry = true; 139095820184SJason M. Bills while (std::getline(logStream, logEntry)) 139195820184SJason M. Bills { 1392c4bf6374SJason M. Bills std::string idStr; 1393e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1394c4bf6374SJason M. Bills { 1395c4bf6374SJason M. Bills continue; 1396c4bf6374SJason M. Bills } 1397e85d6b16SJason M. Bills firstEntry = false; 1398e85d6b16SJason M. Bills 1399de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1400ac992cdeSJason M. Bills LogParseError status = 1401ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1402ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1403ac992cdeSJason M. Bills { 1404ac992cdeSJason M. Bills continue; 1405ac992cdeSJason M. Bills } 1406ac992cdeSJason M. Bills if (status != LogParseError::success) 1407c4bf6374SJason M. Bills { 1408c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1409c4bf6374SJason M. Bills return; 1410c4bf6374SJason M. Bills } 1411de703c5dSJason M. Bills 1412de703c5dSJason M. Bills entryCount++; 1413de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1414de703c5dSJason M. Bills // start) and top (number of entries to display) 14153648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1416de703c5dSJason M. Bills { 1417de703c5dSJason M. Bills continue; 1418de703c5dSJason M. Bills } 1419de703c5dSJason M. Bills 1420de703c5dSJason M. Bills logEntryArray.push_back(std::move(bmcLogEntry)); 1421c4bf6374SJason M. Bills } 142295820184SJason M. Bills } 1423c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 14243648c8beSEd Tanous if (skip + top < entryCount) 1425c4bf6374SJason M. Bills { 1426c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 14274978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 14283648c8beSEd Tanous std::to_string(skip + top); 1429c4bf6374SJason M. Bills } 14307e860f15SJohn Edward Broadbent }); 1431897967deSJason M. Bills } 1432897967deSJason M. Bills 14337e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1434897967deSJason M. Bills { 14357e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 143622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1437ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 14387e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 143945ca1b86SEd Tanous [&app](const crow::Request& req, 14407e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 144122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 14423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 144345ca1b86SEd Tanous { 144445ca1b86SEd Tanous return; 144545ca1b86SEd Tanous } 144622d268cbSEd Tanous 144722d268cbSEd Tanous if (systemName != "system") 144822d268cbSEd Tanous { 144922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 145022d268cbSEd Tanous systemName); 145122d268cbSEd Tanous return; 145222d268cbSEd Tanous } 145322d268cbSEd Tanous 14547e860f15SJohn Edward Broadbent const std::string& targetID = param; 14558d1b46d7Szhanghch05 14567e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 14577e860f15SJohn Edward Broadbent // entry to find the target entry 1458897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1459897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1460897967deSJason M. Bills std::string logEntry; 1461897967deSJason M. Bills 14627e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 14637e860f15SJohn Edward Broadbent // backwards 1464002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1465002d39b4SEd Tanous it++) 1466897967deSJason M. Bills { 1467897967deSJason M. Bills std::ifstream logStream(*it); 1468897967deSJason M. Bills if (!logStream.is_open()) 1469897967deSJason M. Bills { 1470897967deSJason M. Bills continue; 1471897967deSJason M. Bills } 1472897967deSJason M. Bills 1473897967deSJason M. Bills // Reset the unique ID on the first entry 1474897967deSJason M. Bills bool firstEntry = true; 1475897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1476897967deSJason M. Bills { 1477897967deSJason M. Bills std::string idStr; 1478897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1479897967deSJason M. Bills { 1480897967deSJason M. Bills continue; 1481897967deSJason M. Bills } 1482897967deSJason M. Bills firstEntry = false; 1483897967deSJason M. Bills 1484897967deSJason M. Bills if (idStr == targetID) 1485897967deSJason M. Bills { 1486de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1487ac992cdeSJason M. Bills LogParseError status = 1488ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1489ac992cdeSJason M. Bills if (status != LogParseError::success) 1490897967deSJason M. Bills { 1491897967deSJason M. Bills messages::internalError(asyncResp->res); 1492897967deSJason M. Bills return; 1493897967deSJason M. Bills } 1494d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1495897967deSJason M. Bills return; 1496897967deSJason M. Bills } 1497897967deSJason M. Bills } 1498897967deSJason M. Bills } 1499897967deSJason M. Bills // Requested ID was not found 15009db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 15017e860f15SJohn Edward Broadbent }); 150208a4e4b5SAnthony Wilson } 150308a4e4b5SAnthony Wilson 15047e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 150508a4e4b5SAnthony Wilson { 150622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1507ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1508002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1509002d39b4SEd Tanous [&app](const crow::Request& req, 151022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 151122d268cbSEd Tanous const std::string& systemName) { 15123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 151345ca1b86SEd Tanous { 151445ca1b86SEd Tanous return; 151545ca1b86SEd Tanous } 151622d268cbSEd Tanous if (systemName != "system") 151722d268cbSEd Tanous { 151822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 151922d268cbSEd Tanous systemName); 152022d268cbSEd Tanous return; 152122d268cbSEd Tanous } 152222d268cbSEd Tanous 15237e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15247e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 152508a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 152608a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 152708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 152808a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 152908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 153008a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 153108a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 153208a4e4b5SAnthony Wilson 1533cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1534cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 1535cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 1536cb92c03bSAndrew Geissler [asyncResp](const boost::system::error_code ec, 1537914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1538cb92c03bSAndrew Geissler if (ec) 1539cb92c03bSAndrew Geissler { 1540cb92c03bSAndrew Geissler // TODO Handle for specific error code 1541cb92c03bSAndrew Geissler BMCWEB_LOG_ERROR 1542002d39b4SEd Tanous << "getLogEntriesIfaceData resp_handler got error " << ec; 1543cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1544cb92c03bSAndrew Geissler return; 1545cb92c03bSAndrew Geissler } 1546002d39b4SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 1547cb92c03bSAndrew Geissler entriesArray = nlohmann::json::array(); 15489eb808c1SEd Tanous for (const auto& objectPath : resp) 1549cb92c03bSAndrew Geissler { 1550914e2d5dSEd Tanous const uint32_t* id = nullptr; 1551c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1552c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1553914e2d5dSEd Tanous const std::string* severity = nullptr; 1554914e2d5dSEd Tanous const std::string* message = nullptr; 1555914e2d5dSEd Tanous const std::string* filePath = nullptr; 15569c11a172SVijay Lobo const std::string* resolution = nullptr; 155775710de2SXiaochao Ma bool resolved = false; 1558*9017faf2SAbhishek Patel const std::string* notify = nullptr; 1559*9017faf2SAbhishek Patel 15609eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1561f86bb901SAdriana Kobylak { 1562f86bb901SAdriana Kobylak if (interfaceMap.first == 1563f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1564f86bb901SAdriana Kobylak { 1565002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1566cb92c03bSAndrew Geissler { 1567cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1568cb92c03bSAndrew Geissler { 1569002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1570cb92c03bSAndrew Geissler } 1571cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1572cb92c03bSAndrew Geissler { 1573002d39b4SEd Tanous timestamp = 1574002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15757e860f15SJohn Edward Broadbent } 1576002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 15777e860f15SJohn Edward Broadbent { 1578002d39b4SEd Tanous updateTimestamp = 1579002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 15807e860f15SJohn Edward Broadbent } 15817e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 15827e860f15SJohn Edward Broadbent { 15837e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 15847e860f15SJohn Edward Broadbent &propertyMap.second); 15857e860f15SJohn Edward Broadbent } 15869c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 15879c11a172SVijay Lobo { 15889c11a172SVijay Lobo resolution = std::get_if<std::string>( 15899c11a172SVijay Lobo &propertyMap.second); 15909c11a172SVijay Lobo } 15917e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 15927e860f15SJohn Edward Broadbent { 15937e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 15947e860f15SJohn Edward Broadbent &propertyMap.second); 15957e860f15SJohn Edward Broadbent } 15967e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 15977e860f15SJohn Edward Broadbent { 1598914e2d5dSEd Tanous const bool* resolveptr = 1599002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 16007e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 16017e860f15SJohn Edward Broadbent { 1602002d39b4SEd Tanous messages::internalError(asyncResp->res); 16037e860f15SJohn Edward Broadbent return; 16047e860f15SJohn Edward Broadbent } 16057e860f15SJohn Edward Broadbent resolved = *resolveptr; 16067e860f15SJohn Edward Broadbent } 1607*9017faf2SAbhishek Patel else if (propertyMap.first == 1608*9017faf2SAbhishek Patel "ServiceProviderNotify") 1609*9017faf2SAbhishek Patel { 1610*9017faf2SAbhishek Patel notify = std::get_if<std::string>( 1611*9017faf2SAbhishek Patel &propertyMap.second); 1612*9017faf2SAbhishek Patel if (notify == nullptr) 1613*9017faf2SAbhishek Patel { 1614*9017faf2SAbhishek Patel messages::internalError(asyncResp->res); 1615*9017faf2SAbhishek Patel return; 1616*9017faf2SAbhishek Patel } 1617*9017faf2SAbhishek Patel } 16187e860f15SJohn Edward Broadbent } 16197e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 16207e860f15SJohn Edward Broadbent severity == nullptr) 16217e860f15SJohn Edward Broadbent { 16227e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 16237e860f15SJohn Edward Broadbent return; 16247e860f15SJohn Edward Broadbent } 16257e860f15SJohn Edward Broadbent } 16267e860f15SJohn Edward Broadbent else if (interfaceMap.first == 16277e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 16287e860f15SJohn Edward Broadbent { 1629002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 16307e860f15SJohn Edward Broadbent { 16317e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 16327e860f15SJohn Edward Broadbent { 16337e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 16347e860f15SJohn Edward Broadbent &propertyMap.second); 16357e860f15SJohn Edward Broadbent } 16367e860f15SJohn Edward Broadbent } 16377e860f15SJohn Edward Broadbent } 16387e860f15SJohn Edward Broadbent } 16397e860f15SJohn Edward Broadbent // Object path without the 16407e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 16417e860f15SJohn Edward Broadbent // and continue. 16427e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1643c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1644c419c759SEd Tanous updateTimestamp == nullptr) 16457e860f15SJohn Edward Broadbent { 16467e860f15SJohn Edward Broadbent continue; 16477e860f15SJohn Edward Broadbent } 16487e860f15SJohn Edward Broadbent entriesArray.push_back({}); 16497e860f15SJohn Edward Broadbent nlohmann::json& thisEntry = entriesArray.back(); 16509c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 16517e860f15SJohn Edward Broadbent thisEntry["@odata.id"] = 16520fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16537e860f15SJohn Edward Broadbent std::to_string(*id); 16547e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 16557e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 16567e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 16577e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 16589c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 16599c11a172SVijay Lobo { 16609c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 16619c11a172SVijay Lobo } 1662*9017faf2SAbhishek Patel std::optional<bool> notifyAction = 1663*9017faf2SAbhishek Patel getProviderNotifyAction(*notify); 1664*9017faf2SAbhishek Patel if (notifyAction) 1665*9017faf2SAbhishek Patel { 1666*9017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 1667*9017faf2SAbhishek Patel } 16687e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 16697e860f15SJohn Edward Broadbent thisEntry["Severity"] = 16707e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 16717e860f15SJohn Edward Broadbent thisEntry["Created"] = 16722b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 16737e860f15SJohn Edward Broadbent thisEntry["Modified"] = 16742b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 16757e860f15SJohn Edward Broadbent if (filePath != nullptr) 16767e860f15SJohn Edward Broadbent { 16777e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 16780fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 16797e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 16807e860f15SJohn Edward Broadbent } 16817e860f15SJohn Edward Broadbent } 1682002d39b4SEd Tanous std::sort( 1683002d39b4SEd Tanous entriesArray.begin(), entriesArray.end(), 1684002d39b4SEd Tanous [](const nlohmann::json& left, const nlohmann::json& right) { 16857e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 16867e860f15SJohn Edward Broadbent }); 16877e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 16887e860f15SJohn Edward Broadbent entriesArray.size(); 16897e860f15SJohn Edward Broadbent }, 16907e860f15SJohn Edward Broadbent "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 16917e860f15SJohn Edward Broadbent "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 16927e860f15SJohn Edward Broadbent }); 16937e860f15SJohn Edward Broadbent } 16947e860f15SJohn Edward Broadbent 16957e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 16967e860f15SJohn Edward Broadbent { 16977e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 169822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1699ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1700002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1701002d39b4SEd Tanous [&app](const crow::Request& req, 17027e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 170322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 17043ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 17057e860f15SJohn Edward Broadbent { 170645ca1b86SEd Tanous return; 170745ca1b86SEd Tanous } 170822d268cbSEd Tanous if (systemName != "system") 170922d268cbSEd Tanous { 171022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 171122d268cbSEd Tanous systemName); 171222d268cbSEd Tanous return; 171322d268cbSEd Tanous } 171422d268cbSEd Tanous 17157e860f15SJohn Edward Broadbent std::string entryID = param; 17167e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 17177e860f15SJohn Edward Broadbent 17187e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 17197e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1720d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1721d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1722d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 1723002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1724b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 17257e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 17267e860f15SJohn Edward Broadbent { 1727d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1728d1bde9e5SKrzysztof Grobelny entryID); 17297e860f15SJohn Edward Broadbent return; 17307e860f15SJohn Edward Broadbent } 17317e860f15SJohn Edward Broadbent if (ec) 17327e860f15SJohn Edward Broadbent { 17330fda0f12SGeorge Liu BMCWEB_LOG_ERROR 1734002d39b4SEd Tanous << "EventLogEntry (DBus) resp_handler got error " << ec; 17357e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 17367e860f15SJohn Edward Broadbent return; 17377e860f15SJohn Edward Broadbent } 1738914e2d5dSEd Tanous const uint32_t* id = nullptr; 1739c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1740c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1741914e2d5dSEd Tanous const std::string* severity = nullptr; 1742914e2d5dSEd Tanous const std::string* message = nullptr; 1743914e2d5dSEd Tanous const std::string* filePath = nullptr; 17449c11a172SVijay Lobo const std::string* resolution = nullptr; 17457e860f15SJohn Edward Broadbent bool resolved = false; 1746*9017faf2SAbhishek Patel const std::string* notify = nullptr; 17477e860f15SJohn Edward Broadbent 1748d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1749d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1750d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 17519c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 1752*9017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 1753*9017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1754d1bde9e5SKrzysztof Grobelny 1755d1bde9e5SKrzysztof Grobelny if (!success) 175675710de2SXiaochao Ma { 175775710de2SXiaochao Ma messages::internalError(asyncResp->res); 175875710de2SXiaochao Ma return; 175975710de2SXiaochao Ma } 1760d1bde9e5SKrzysztof Grobelny 1761002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 1762*9017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 1763*9017faf2SAbhishek Patel notify == nullptr) 1764f86bb901SAdriana Kobylak { 1765ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 1766271584abSEd Tanous return; 1767271584abSEd Tanous } 1768*9017faf2SAbhishek Patel 1769f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 17709c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 1771f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.id"] = 17720fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1773f86bb901SAdriana Kobylak std::to_string(*id); 177445ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 1775f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 1776f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 1777f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 1778*9017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 1779*9017faf2SAbhishek Patel if (notifyAction) 1780*9017faf2SAbhishek Patel { 1781*9017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 1782*9017faf2SAbhishek Patel *notifyAction; 1783*9017faf2SAbhishek Patel } 17849c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 17859c11a172SVijay Lobo { 17869c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 17879c11a172SVijay Lobo } 1788f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 1789f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 1790f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 1791f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 17922b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 1793f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 17942b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 1795f86bb901SAdriana Kobylak if (filePath != nullptr) 1796f86bb901SAdriana Kobylak { 1797f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 1798e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 1799e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 1800f86bb901SAdriana Kobylak } 1801d1bde9e5SKrzysztof Grobelny }); 18027e860f15SJohn Edward Broadbent }); 1803336e96c6SChicago Duan 18047e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 180522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1806ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 18077e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 180845ca1b86SEd Tanous [&app](const crow::Request& req, 18097e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 181022d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 18113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 181245ca1b86SEd Tanous { 181345ca1b86SEd Tanous return; 181445ca1b86SEd Tanous } 181522d268cbSEd Tanous if (systemName != "system") 181622d268cbSEd Tanous { 181722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 181822d268cbSEd Tanous systemName); 181922d268cbSEd Tanous return; 182022d268cbSEd Tanous } 182175710de2SXiaochao Ma std::optional<bool> resolved; 182275710de2SXiaochao Ma 182315ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 18247e860f15SJohn Edward Broadbent resolved)) 182575710de2SXiaochao Ma { 182675710de2SXiaochao Ma return; 182775710de2SXiaochao Ma } 182875710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "Set Resolved"; 182975710de2SXiaochao Ma 183075710de2SXiaochao Ma crow::connections::systemBus->async_method_call( 18314f48d5f6SEd Tanous [asyncResp, entryId](const boost::system::error_code ec) { 183275710de2SXiaochao Ma if (ec) 183375710de2SXiaochao Ma { 183475710de2SXiaochao Ma BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 183575710de2SXiaochao Ma messages::internalError(asyncResp->res); 183675710de2SXiaochao Ma return; 183775710de2SXiaochao Ma } 183875710de2SXiaochao Ma }, 183975710de2SXiaochao Ma "xyz.openbmc_project.Logging", 184075710de2SXiaochao Ma "/xyz/openbmc_project/logging/entry/" + entryId, 184175710de2SXiaochao Ma "org.freedesktop.DBus.Properties", "Set", 184275710de2SXiaochao Ma "xyz.openbmc_project.Logging.Entry", "Resolved", 1843168e20c1SEd Tanous dbus::utility::DbusVariantType(*resolved)); 18447e860f15SJohn Edward Broadbent }); 184575710de2SXiaochao Ma 18467e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 184722d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1848ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 1849ed398213SEd Tanous 1850002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 1851002d39b4SEd Tanous [&app](const crow::Request& req, 1852002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 185322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 18543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1855336e96c6SChicago Duan { 185645ca1b86SEd Tanous return; 185745ca1b86SEd Tanous } 185822d268cbSEd Tanous if (systemName != "system") 185922d268cbSEd Tanous { 186022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 186122d268cbSEd Tanous systemName); 186222d268cbSEd Tanous return; 186322d268cbSEd Tanous } 1864336e96c6SChicago Duan BMCWEB_LOG_DEBUG << "Do delete single event entries."; 1865336e96c6SChicago Duan 18667e860f15SJohn Edward Broadbent std::string entryID = param; 1867336e96c6SChicago Duan 1868336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 1869336e96c6SChicago Duan 1870336e96c6SChicago Duan // Process response from Logging service. 1871002d39b4SEd Tanous auto respHandler = 1872002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec) { 1873002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done"; 1874336e96c6SChicago Duan if (ec) 1875336e96c6SChicago Duan { 18763de8d8baSGeorge Liu if (ec.value() == EBADR) 18773de8d8baSGeorge Liu { 187845ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 187945ca1b86SEd Tanous entryID); 18803de8d8baSGeorge Liu return; 18813de8d8baSGeorge Liu } 1882336e96c6SChicago Duan // TODO Handle for specific error code 18830fda0f12SGeorge Liu BMCWEB_LOG_ERROR 18840fda0f12SGeorge Liu << "EventLogEntry (DBus) doDelete respHandler got error " 1885336e96c6SChicago Duan << ec; 1886336e96c6SChicago Duan asyncResp->res.result( 1887336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 1888336e96c6SChicago Duan return; 1889336e96c6SChicago Duan } 1890336e96c6SChicago Duan 1891336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 1892336e96c6SChicago Duan }; 1893336e96c6SChicago Duan 1894336e96c6SChicago Duan // Make call to Logging service to request Delete Log 1895336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 1896336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 1897336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 1898336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 18997e860f15SJohn Edward Broadbent }); 1900400fd1fbSAdriana Kobylak } 1901400fd1fbSAdriana Kobylak 19027e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app) 1903400fd1fbSAdriana Kobylak { 19040fda0f12SGeorge Liu BMCWEB_ROUTE( 19050fda0f12SGeorge Liu app, 190622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment") 1907ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 19087e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 190945ca1b86SEd Tanous [&app](const crow::Request& req, 19107e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 191122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19137e860f15SJohn Edward Broadbent { 191445ca1b86SEd Tanous return; 191545ca1b86SEd Tanous } 191699351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 191799351cd8SEd Tanous req.getHeaderValue("Accept"), 19184a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 1919400fd1fbSAdriana Kobylak { 1920002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 1921400fd1fbSAdriana Kobylak return; 1922400fd1fbSAdriana Kobylak } 192322d268cbSEd Tanous if (systemName != "system") 192422d268cbSEd Tanous { 192522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 192622d268cbSEd Tanous systemName); 192722d268cbSEd Tanous return; 192822d268cbSEd Tanous } 1929400fd1fbSAdriana Kobylak 19307e860f15SJohn Edward Broadbent std::string entryID = param; 1931400fd1fbSAdriana Kobylak dbus::utility::escapePathForDbus(entryID); 1932400fd1fbSAdriana Kobylak 1933400fd1fbSAdriana Kobylak crow::connections::systemBus->async_method_call( 1934002d39b4SEd Tanous [asyncResp, entryID](const boost::system::error_code ec, 1935400fd1fbSAdriana Kobylak const sdbusplus::message::unix_fd& unixfd) { 1936400fd1fbSAdriana Kobylak if (ec.value() == EBADR) 1937400fd1fbSAdriana Kobylak { 1938002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "EventLogAttachment", 1939002d39b4SEd Tanous entryID); 1940400fd1fbSAdriana Kobylak return; 1941400fd1fbSAdriana Kobylak } 1942400fd1fbSAdriana Kobylak if (ec) 1943400fd1fbSAdriana Kobylak { 1944400fd1fbSAdriana Kobylak BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1945400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1946400fd1fbSAdriana Kobylak return; 1947400fd1fbSAdriana Kobylak } 1948400fd1fbSAdriana Kobylak 1949400fd1fbSAdriana Kobylak int fd = -1; 1950400fd1fbSAdriana Kobylak fd = dup(unixfd); 1951400fd1fbSAdriana Kobylak if (fd == -1) 1952400fd1fbSAdriana Kobylak { 1953400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1954400fd1fbSAdriana Kobylak return; 1955400fd1fbSAdriana Kobylak } 1956400fd1fbSAdriana Kobylak 1957400fd1fbSAdriana Kobylak long long int size = lseek(fd, 0, SEEK_END); 1958400fd1fbSAdriana Kobylak if (size == -1) 1959400fd1fbSAdriana Kobylak { 1960400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1961400fd1fbSAdriana Kobylak return; 1962400fd1fbSAdriana Kobylak } 1963400fd1fbSAdriana Kobylak 1964400fd1fbSAdriana Kobylak // Arbitrary max size of 64kb 1965400fd1fbSAdriana Kobylak constexpr int maxFileSize = 65536; 1966400fd1fbSAdriana Kobylak if (size > maxFileSize) 1967400fd1fbSAdriana Kobylak { 1968002d39b4SEd Tanous BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of " 1969400fd1fbSAdriana Kobylak << maxFileSize; 1970400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1971400fd1fbSAdriana Kobylak return; 1972400fd1fbSAdriana Kobylak } 1973400fd1fbSAdriana Kobylak std::vector<char> data(static_cast<size_t>(size)); 1974400fd1fbSAdriana Kobylak long long int rc = lseek(fd, 0, SEEK_SET); 1975400fd1fbSAdriana Kobylak if (rc == -1) 1976400fd1fbSAdriana Kobylak { 1977400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1978400fd1fbSAdriana Kobylak return; 1979400fd1fbSAdriana Kobylak } 1980400fd1fbSAdriana Kobylak rc = read(fd, data.data(), data.size()); 1981400fd1fbSAdriana Kobylak if ((rc == -1) || (rc != size)) 1982400fd1fbSAdriana Kobylak { 1983400fd1fbSAdriana Kobylak messages::internalError(asyncResp->res); 1984400fd1fbSAdriana Kobylak return; 1985400fd1fbSAdriana Kobylak } 1986400fd1fbSAdriana Kobylak close(fd); 1987400fd1fbSAdriana Kobylak 1988400fd1fbSAdriana Kobylak std::string_view strData(data.data(), data.size()); 1989002d39b4SEd Tanous std::string output = crow::utility::base64encode(strData); 1990400fd1fbSAdriana Kobylak 1991d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 1992400fd1fbSAdriana Kobylak "application/octet-stream"); 1993d9f6c621SEd Tanous asyncResp->res.addHeader( 1994d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 1995400fd1fbSAdriana Kobylak asyncResp->res.body() = std::move(output); 1996400fd1fbSAdriana Kobylak }, 1997400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging", 1998400fd1fbSAdriana Kobylak "/xyz/openbmc_project/logging/entry/" + entryID, 1999400fd1fbSAdriana Kobylak "xyz.openbmc_project.Logging.Entry", "GetEntry"); 20007e860f15SJohn Edward Broadbent }); 20011da66f75SEd Tanous } 20021da66f75SEd Tanous 2003b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2004b7028ebfSSpencer Ku 2005b7028ebfSSpencer Ku inline bool 2006b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2007b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2008b7028ebfSSpencer Ku { 2009b7028ebfSSpencer Ku std::error_code ec; 2010b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2011b7028ebfSSpencer Ku if (ec) 2012b7028ebfSSpencer Ku { 2013b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << ec.message(); 2014b7028ebfSSpencer Ku return false; 2015b7028ebfSSpencer Ku } 2016b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2017b7028ebfSSpencer Ku { 2018b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2019b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2020b7028ebfSSpencer Ku // path 202111ba3979SEd Tanous if (filename.starts_with("log")) 2022b7028ebfSSpencer Ku { 2023b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2024b7028ebfSSpencer Ku } 2025b7028ebfSSpencer Ku } 2026b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2027b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2028b7028ebfSSpencer Ku // descending order. 2029b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2030b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2031b7028ebfSSpencer Ku 2032b7028ebfSSpencer Ku return true; 2033b7028ebfSSpencer Ku } 2034b7028ebfSSpencer Ku 203502cad96eSEd Tanous inline bool getHostLoggerEntries( 203602cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 203702cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2038b7028ebfSSpencer Ku { 2039b7028ebfSSpencer Ku GzFileReader logFile; 2040b7028ebfSSpencer Ku 2041b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2042b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2043b7028ebfSSpencer Ku { 2044b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2045b7028ebfSSpencer Ku { 2046b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to expose host logs"; 2047b7028ebfSSpencer Ku return false; 2048b7028ebfSSpencer Ku } 2049b7028ebfSSpencer Ku } 2050b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2051b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2052b7028ebfSSpencer Ku if (!lastMessage.empty()) 2053b7028ebfSSpencer Ku { 2054b7028ebfSSpencer Ku logCount++; 2055b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2056b7028ebfSSpencer Ku { 2057b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2058b7028ebfSSpencer Ku } 2059b7028ebfSSpencer Ku } 2060b7028ebfSSpencer Ku return true; 2061b7028ebfSSpencer Ku } 2062b7028ebfSSpencer Ku 2063b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2064b7028ebfSSpencer Ku const std::string& msg, 20656d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2066b7028ebfSSpencer Ku { 2067b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 20689c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 20696d6574c9SJason M. Bills logEntryJson["@odata.id"] = 2070b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" + 20716d6574c9SJason M. Bills logEntryID; 20726d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 20736d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 20746d6574c9SJason M. Bills logEntryJson["Message"] = msg; 20756d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 20766d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 20776d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2078b7028ebfSSpencer Ku } 2079b7028ebfSSpencer Ku 2080b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2081b7028ebfSSpencer Ku { 208222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2083b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 20841476687dSEd Tanous .methods(boost::beast::http::verb::get)( 20851476687dSEd Tanous [&app](const crow::Request& req, 208622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 208722d268cbSEd Tanous const std::string& systemName) { 20883ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 208945ca1b86SEd Tanous { 209045ca1b86SEd Tanous return; 209145ca1b86SEd Tanous } 209222d268cbSEd Tanous if (systemName != "system") 209322d268cbSEd Tanous { 209422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 209522d268cbSEd Tanous systemName); 209622d268cbSEd Tanous return; 209722d268cbSEd Tanous } 2098b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2099b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2100b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2101b7028ebfSSpencer Ku "#LogService.v1_1_0.LogService"; 2102b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2103b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2104b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 21051476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 21061476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2107b7028ebfSSpencer Ku }); 2108b7028ebfSSpencer Ku } 2109b7028ebfSSpencer Ku 2110b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2111b7028ebfSSpencer Ku { 2112b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 211322d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2114b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2115002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2116002d39b4SEd Tanous [&app](const crow::Request& req, 211722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 211822d268cbSEd Tanous const std::string& systemName) { 2119c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2120c937d2bfSEd Tanous .canDelegateTop = true, 2121c937d2bfSEd Tanous .canDelegateSkip = true, 2122c937d2bfSEd Tanous }; 2123c937d2bfSEd Tanous query_param::Query delegatedQuery; 2124c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 21253ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2126b7028ebfSSpencer Ku { 2127b7028ebfSSpencer Ku return; 2128b7028ebfSSpencer Ku } 212922d268cbSEd Tanous if (systemName != "system") 213022d268cbSEd Tanous { 213122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 213222d268cbSEd Tanous systemName); 213322d268cbSEd Tanous return; 213422d268cbSEd Tanous } 2135b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2136b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2137b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2138b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2139b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2140b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2141b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 21420fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2143b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2144b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2145b7028ebfSSpencer Ku 2146b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2147b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2148b7028ebfSSpencer Ku { 2149b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2150b7028ebfSSpencer Ku return; 2151b7028ebfSSpencer Ku } 21523648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 21533648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 21545143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2155b7028ebfSSpencer Ku size_t logCount = 0; 2156b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2157b7028ebfSSpencer Ku // control by skip and top. 2158b7028ebfSSpencer Ku std::vector<std::string> logEntries; 21593648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 21603648c8beSEd Tanous logCount)) 2161b7028ebfSSpencer Ku { 2162b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2163b7028ebfSSpencer Ku return; 2164b7028ebfSSpencer Ku } 2165b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2166b7028ebfSSpencer Ku // log count 216726f6976fSEd Tanous if (logEntries.empty()) 2168b7028ebfSSpencer Ku { 2169b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2170b7028ebfSSpencer Ku return; 2171b7028ebfSSpencer Ku } 217226f6976fSEd Tanous if (!logEntries.empty()) 2173b7028ebfSSpencer Ku { 2174b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2175b7028ebfSSpencer Ku { 21766d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 21773648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 21783648c8beSEd Tanous hostLogEntry); 21796d6574c9SJason M. Bills logEntryArray.push_back(std::move(hostLogEntry)); 2180b7028ebfSSpencer Ku } 2181b7028ebfSSpencer Ku 2182b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 21833648c8beSEd Tanous if (skip + top < logCount) 2184b7028ebfSSpencer Ku { 2185b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 21860fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 21873648c8beSEd Tanous std::to_string(skip + top); 2188b7028ebfSSpencer Ku } 2189b7028ebfSSpencer Ku } 2190b7028ebfSSpencer Ku }); 2191b7028ebfSSpencer Ku } 2192b7028ebfSSpencer Ku 2193b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2194b7028ebfSSpencer Ku { 2195b7028ebfSSpencer Ku BMCWEB_ROUTE( 219622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2197b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2198b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 219945ca1b86SEd Tanous [&app](const crow::Request& req, 2200b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 220122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 22023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 220345ca1b86SEd Tanous { 220445ca1b86SEd Tanous return; 220545ca1b86SEd Tanous } 220622d268cbSEd Tanous if (systemName != "system") 220722d268cbSEd Tanous { 220822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 220922d268cbSEd Tanous systemName); 221022d268cbSEd Tanous return; 221122d268cbSEd Tanous } 2212b7028ebfSSpencer Ku const std::string& targetID = param; 2213b7028ebfSSpencer Ku 2214b7028ebfSSpencer Ku uint64_t idInt = 0; 2215ca45aa3cSEd Tanous 2216ca45aa3cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2217ca45aa3cSEd Tanous const char* end = targetID.data() + targetID.size(); 2218ca45aa3cSEd Tanous 2219ca45aa3cSEd Tanous auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt); 22209db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 22219db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2222b7028ebfSSpencer Ku { 22239db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2224b7028ebfSSpencer Ku return; 2225b7028ebfSSpencer Ku } 2226b7028ebfSSpencer Ku 2227b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2228b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2229b7028ebfSSpencer Ku { 2230b7028ebfSSpencer Ku BMCWEB_LOG_ERROR << "fail to get host log file path"; 2231b7028ebfSSpencer Ku return; 2232b7028ebfSSpencer Ku } 2233b7028ebfSSpencer Ku 2234b7028ebfSSpencer Ku size_t logCount = 0; 22353648c8beSEd Tanous size_t top = 1; 2236b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2237b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2238b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2239b7028ebfSSpencer Ku // get that entry 2240002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2241002d39b4SEd Tanous logCount)) 2242b7028ebfSSpencer Ku { 2243b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2244b7028ebfSSpencer Ku return; 2245b7028ebfSSpencer Ku } 2246b7028ebfSSpencer Ku 2247b7028ebfSSpencer Ku if (!logEntries.empty()) 2248b7028ebfSSpencer Ku { 22496d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 22506d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 22516d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2252b7028ebfSSpencer Ku return; 2253b7028ebfSSpencer Ku } 2254b7028ebfSSpencer Ku 2255b7028ebfSSpencer Ku // Requested ID was not found 22569db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2257b7028ebfSSpencer Ku }); 2258b7028ebfSSpencer Ku } 2259b7028ebfSSpencer Ku 2260fdd26906SClaire Weinan constexpr char const* dumpManagerIface = 2261fdd26906SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll"; 2262dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2263fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2264fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 22651da66f75SEd Tanous { 22663ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 226745ca1b86SEd Tanous { 226845ca1b86SEd Tanous return; 226945ca1b86SEd Tanous } 22707e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 22717e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2272e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 22731da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2274e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2275e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2276002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2277e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 22781da66f75SEd Tanous "Collection of LogServices for this Manager"; 2279002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2280c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2281fdd26906SClaire Weinan 2282c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2283613dabeaSEd Tanous nlohmann::json::object_t journal; 2284613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2285613dabeaSEd Tanous logServiceArray.push_back(std::move(journal)); 2286c4bf6374SJason M. Bills #endif 2287fdd26906SClaire Weinan 2288fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2289fdd26906SClaire Weinan 2290fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 2291fdd26906SClaire Weinan auto respHandler = 2292fdd26906SClaire Weinan [asyncResp]( 2293fdd26906SClaire Weinan const boost::system::error_code ec, 2294fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2295fdd26906SClaire Weinan if (ec) 2296fdd26906SClaire Weinan { 2297fdd26906SClaire Weinan BMCWEB_LOG_ERROR 2298dd72e87bSClaire Weinan << "handleBMCLogServicesCollectionGet respHandler got error " 2299fdd26906SClaire Weinan << ec; 2300fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2301fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2302fdd26906SClaire Weinan return; 2303fdd26906SClaire Weinan } 2304fdd26906SClaire Weinan 2305fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2306fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2307fdd26906SClaire Weinan 2308fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2309fdd26906SClaire Weinan { 2310fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2311fdd26906SClaire Weinan { 2312613dabeaSEd Tanous nlohmann::json::object_t member; 2313613dabeaSEd Tanous member["@odata.id"] = 2314613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2315613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2316fdd26906SClaire Weinan } 2317fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2318fdd26906SClaire Weinan { 2319613dabeaSEd Tanous nlohmann::json::object_t member; 2320613dabeaSEd Tanous member["@odata.id"] = 2321613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2322613dabeaSEd Tanous logServiceArrayLocal.push_back(std::move(member)); 2323fdd26906SClaire Weinan } 2324fdd26906SClaire Weinan } 2325fdd26906SClaire Weinan 2326e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2327fdd26906SClaire Weinan logServiceArrayLocal.size(); 2328fdd26906SClaire Weinan }; 2329fdd26906SClaire Weinan 2330fdd26906SClaire Weinan crow::connections::systemBus->async_method_call( 2331fdd26906SClaire Weinan respHandler, "xyz.openbmc_project.ObjectMapper", 2332fdd26906SClaire Weinan "/xyz/openbmc_project/object_mapper", 2333fdd26906SClaire Weinan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 2334fdd26906SClaire Weinan "/xyz/openbmc_project/dump", 0, 2335fdd26906SClaire Weinan std::array<const char*, 1>{dumpManagerIface}); 2336fdd26906SClaire Weinan #endif 2337fdd26906SClaire Weinan } 2338fdd26906SClaire Weinan 2339fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2340fdd26906SClaire Weinan { 2341fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2342fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2343fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2344dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2345e1f26343SJason M. Bills } 2346e1f26343SJason M. Bills 23477e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2348e1f26343SJason M. Bills { 23497e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2350ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 23517e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 235245ca1b86SEd Tanous [&app](const crow::Request& req, 235345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23557e860f15SJohn Edward Broadbent { 235645ca1b86SEd Tanous return; 235745ca1b86SEd Tanous } 2358e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2359e1f26343SJason M. Bills "#LogService.v1_1_0.LogService"; 23600f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 23610f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2362002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2363002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2364c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "BMC Journal"; 2365e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 23667c8c4058STejas Patil 23677c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 23682b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2369002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 23707c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 23717c8c4058STejas Patil redfishDateTimeOffset.second; 23727c8c4058STejas Patil 23731476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 23741476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 23757e860f15SJohn Edward Broadbent }); 2376e1f26343SJason M. Bills } 2377e1f26343SJason M. Bills 23783a48b3a2SJason M. Bills static int 23793a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2380e1f26343SJason M. Bills sd_journal* journal, 23813a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2382e1f26343SJason M. Bills { 2383e1f26343SJason M. Bills // Get the Log Entry contents 2384e1f26343SJason M. Bills int ret = 0; 2385e1f26343SJason M. Bills 2386a8fe54f0SJason M. Bills std::string message; 2387a8fe54f0SJason M. Bills std::string_view syslogID; 2388a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2389a8fe54f0SJason M. Bills if (ret < 0) 2390a8fe54f0SJason M. Bills { 2391a8fe54f0SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: " 2392a8fe54f0SJason M. Bills << strerror(-ret); 2393a8fe54f0SJason M. Bills } 2394a8fe54f0SJason M. Bills if (!syslogID.empty()) 2395a8fe54f0SJason M. Bills { 2396a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2397a8fe54f0SJason M. Bills } 2398a8fe54f0SJason M. Bills 239939e77504SEd Tanous std::string_view msg; 240016428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2401e1f26343SJason M. Bills if (ret < 0) 2402e1f26343SJason M. Bills { 2403e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret); 2404e1f26343SJason M. Bills return 1; 2405e1f26343SJason M. Bills } 2406a8fe54f0SJason M. Bills message += std::string(msg); 2407e1f26343SJason M. Bills 2408e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2409271584abSEd Tanous long int severity = 8; // Default to an invalid priority 241016428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2411e1f26343SJason M. Bills if (ret < 0) 2412e1f26343SJason M. Bills { 2413e1f26343SJason M. Bills BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret); 2414e1f26343SJason M. Bills } 2415e1f26343SJason M. Bills 2416e1f26343SJason M. Bills // Get the Created time from the timestamp 241716428a1aSJason M. Bills std::string entryTimeStr; 241816428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2419e1f26343SJason M. Bills { 242016428a1aSJason M. Bills return 1; 2421e1f26343SJason M. Bills } 2422e1f26343SJason M. Bills 2423e1f26343SJason M. Bills // Fill in the log entry with the gathered data 24249c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 242584afc48bSJason M. Bills bmcJournalLogEntryJson["@odata.id"] = 242684afc48bSJason M. Bills "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" + 242784afc48bSJason M. Bills bmcJournalLogEntryID; 242884afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 242984afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 243084afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 243184afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 243284afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2433738c1e61SPatrick Williams : severity <= 4 ? "Warning" 243484afc48bSJason M. Bills : "OK"; 243584afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 243684afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2437e1f26343SJason M. Bills return 0; 2438e1f26343SJason M. Bills } 2439e1f26343SJason M. Bills 24407e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2441e1f26343SJason M. Bills { 24427e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2443ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2444002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2445002d39b4SEd Tanous [&app](const crow::Request& req, 2446002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2447c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2448c937d2bfSEd Tanous .canDelegateTop = true, 2449c937d2bfSEd Tanous .canDelegateSkip = true, 2450c937d2bfSEd Tanous }; 2451c937d2bfSEd Tanous query_param::Query delegatedQuery; 2452c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 24533ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2454193ad2faSJason M. Bills { 2455193ad2faSJason M. Bills return; 2456193ad2faSJason M. Bills } 24573648c8beSEd Tanous 24583648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 24595143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 24603648c8beSEd Tanous 24617e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24627e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2463e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2464e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 24650f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 24660f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2467e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2468e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2469e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 24700fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2471e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2472e1f26343SJason M. Bills 24737e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 24747e860f15SJohn Edward Broadbent // unique ID for each entry 2475e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2476e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2477e1f26343SJason M. Bills if (ret < 0) 2478e1f26343SJason M. Bills { 2479002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2480f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2481e1f26343SJason M. Bills return; 2482e1f26343SJason M. Bills } 24830fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 24840fda0f12SGeorge Liu journalTmp, sd_journal_close); 2485e1f26343SJason M. Bills journalTmp = nullptr; 2486b01bf299SEd Tanous uint64_t entryCount = 0; 2487e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2488e85d6b16SJason M. Bills bool firstEntry = true; 2489e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2490e1f26343SJason M. Bills { 2491193ad2faSJason M. Bills entryCount++; 24927e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 24937e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 24943648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2495193ad2faSJason M. Bills { 2496193ad2faSJason M. Bills continue; 2497193ad2faSJason M. Bills } 2498193ad2faSJason M. Bills 249916428a1aSJason M. Bills std::string idStr; 2500e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2501e1f26343SJason M. Bills { 2502e1f26343SJason M. Bills continue; 2503e1f26343SJason M. Bills } 2504e85d6b16SJason M. Bills firstEntry = false; 2505e85d6b16SJason M. Bills 25063a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2507c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2508c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2509e1f26343SJason M. Bills { 2510f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2511e1f26343SJason M. Bills return; 2512e1f26343SJason M. Bills } 25133a48b3a2SJason M. Bills logEntryArray.push_back(std::move(bmcJournalLogEntry)); 2514e1f26343SJason M. Bills } 2515193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 25163648c8beSEd Tanous if (skip + top < entryCount) 2517193ad2faSJason M. Bills { 2518193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 25190fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 25203648c8beSEd Tanous std::to_string(skip + top); 2521193ad2faSJason M. Bills } 25227e860f15SJohn Edward Broadbent }); 2523e1f26343SJason M. Bills } 2524e1f26343SJason M. Bills 25257e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2526e1f26343SJason M. Bills { 25277e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 25287e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2529ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 25307e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 253145ca1b86SEd Tanous [&app](const crow::Request& req, 25327e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25337e860f15SJohn Edward Broadbent const std::string& entryID) { 25343ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 253545ca1b86SEd Tanous { 253645ca1b86SEd Tanous return; 253745ca1b86SEd Tanous } 2538e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2539e1f26343SJason M. Bills uint64_t ts = 0; 2540271584abSEd Tanous uint64_t index = 0; 25418d1b46d7Szhanghch05 if (!getTimestampFromID(asyncResp, entryID, ts, index)) 2542e1f26343SJason M. Bills { 254316428a1aSJason M. Bills return; 2544e1f26343SJason M. Bills } 2545e1f26343SJason M. Bills 2546e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2547e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2548e1f26343SJason M. Bills if (ret < 0) 2549e1f26343SJason M. Bills { 2550002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret); 2551f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2552e1f26343SJason M. Bills return; 2553e1f26343SJason M. Bills } 2554002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2555002d39b4SEd Tanous journalTmp, sd_journal_close); 2556e1f26343SJason M. Bills journalTmp = nullptr; 25577e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 25587e860f15SJohn Edward Broadbent // index tracking the unique ID 2559af07e3f5SJason M. Bills std::string idStr; 2560af07e3f5SJason M. Bills bool firstEntry = true; 2561e1f26343SJason M. Bills ret = sd_journal_seek_realtime_usec(journal.get(), ts); 25622056b6d1SManojkiran Eda if (ret < 0) 25632056b6d1SManojkiran Eda { 25642056b6d1SManojkiran Eda BMCWEB_LOG_ERROR << "failed to seek to an entry in journal" 25652056b6d1SManojkiran Eda << strerror(-ret); 25662056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 25672056b6d1SManojkiran Eda return; 25682056b6d1SManojkiran Eda } 2569271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2570e1f26343SJason M. Bills { 2571e1f26343SJason M. Bills sd_journal_next(journal.get()); 2572af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2573af07e3f5SJason M. Bills { 2574af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2575af07e3f5SJason M. Bills return; 2576af07e3f5SJason M. Bills } 2577af07e3f5SJason M. Bills firstEntry = false; 2578af07e3f5SJason M. Bills } 2579c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2580af07e3f5SJason M. Bills if (idStr != entryID) 2581c4bf6374SJason M. Bills { 25829db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2583c4bf6374SJason M. Bills return; 2584c4bf6374SJason M. Bills } 2585c4bf6374SJason M. Bills 25863a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2587c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 25883a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2589e1f26343SJason M. Bills { 2590f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2591e1f26343SJason M. Bills return; 2592e1f26343SJason M. Bills } 2593d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 25947e860f15SJohn Edward Broadbent }); 2595c9bb6861Sraviteja-b } 2596c9bb6861Sraviteja-b 2597fdd26906SClaire Weinan inline void 2598fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2599fdd26906SClaire Weinan const std::string& dumpType) 2600c9bb6861Sraviteja-b { 2601fdd26906SClaire Weinan std::string dumpPath; 2602fdd26906SClaire Weinan std::string overWritePolicy; 2603fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2604fdd26906SClaire Weinan 2605fdd26906SClaire Weinan if (dumpType == "BMC") 260645ca1b86SEd Tanous { 2607fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2608fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2609fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2610fdd26906SClaire Weinan } 2611fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2612fdd26906SClaire Weinan { 2613fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2614fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2615fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2616fdd26906SClaire Weinan } 2617fdd26906SClaire Weinan else if (dumpType == "System") 2618fdd26906SClaire Weinan { 2619fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2620fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2621fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2622fdd26906SClaire Weinan } 2623fdd26906SClaire Weinan else 2624fdd26906SClaire Weinan { 2625fdd26906SClaire Weinan BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: " 2626fdd26906SClaire Weinan << dumpType; 2627fdd26906SClaire Weinan messages::internalError(asyncResp->res); 262845ca1b86SEd Tanous return; 262945ca1b86SEd Tanous } 2630fdd26906SClaire Weinan 2631fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2632fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2633c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2634fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2635fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2636fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 26377c8c4058STejas Patil 26387c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 26392b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 26400fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 26417c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 26427c8c4058STejas Patil redfishDateTimeOffset.second; 26437c8c4058STejas Patil 2644fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2645002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 2646fdd26906SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 2647fdd26906SClaire Weinan 2648fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2649fdd26906SClaire Weinan { 2650002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 26511476687dSEd Tanous ["target"] = 2652fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2653fdd26906SClaire Weinan } 2654c9bb6861Sraviteja-b } 2655c9bb6861Sraviteja-b 2656fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2657fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2658fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 26597e860f15SJohn Edward Broadbent { 26603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 266145ca1b86SEd Tanous { 266245ca1b86SEd Tanous return; 266345ca1b86SEd Tanous } 2664fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2665fdd26906SClaire Weinan } 2666c9bb6861Sraviteja-b 266722d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 266822d268cbSEd Tanous crow::App& app, const crow::Request& req, 266922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 267022d268cbSEd Tanous const std::string& chassisId) 267122d268cbSEd Tanous { 267222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 267322d268cbSEd Tanous { 267422d268cbSEd Tanous return; 267522d268cbSEd Tanous } 267622d268cbSEd Tanous if (chassisId != "system") 267722d268cbSEd Tanous { 267822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 267922d268cbSEd Tanous return; 268022d268cbSEd Tanous } 268122d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 268222d268cbSEd Tanous } 268322d268cbSEd Tanous 2684fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2685fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2686fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2687fdd26906SClaire Weinan { 2688fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2689fdd26906SClaire Weinan { 2690fdd26906SClaire Weinan return; 2691fdd26906SClaire Weinan } 2692fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2693fdd26906SClaire Weinan } 2694fdd26906SClaire Weinan 269522d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 269622d268cbSEd Tanous crow::App& app, const crow::Request& req, 269722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 269822d268cbSEd Tanous const std::string& chassisId) 269922d268cbSEd Tanous { 270022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270122d268cbSEd Tanous { 270222d268cbSEd Tanous return; 270322d268cbSEd Tanous } 270422d268cbSEd Tanous if (chassisId != "system") 270522d268cbSEd Tanous { 270622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 270722d268cbSEd Tanous return; 270822d268cbSEd Tanous } 270922d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 271022d268cbSEd Tanous } 271122d268cbSEd Tanous 2712fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2713fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2714fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2715fdd26906SClaire Weinan const std::string& dumpId) 2716fdd26906SClaire Weinan { 2717fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2718fdd26906SClaire Weinan { 2719fdd26906SClaire Weinan return; 2720fdd26906SClaire Weinan } 2721fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2722fdd26906SClaire Weinan } 272322d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 272422d268cbSEd Tanous crow::App& app, const crow::Request& req, 272522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 272622d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 272722d268cbSEd Tanous { 272822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 272922d268cbSEd Tanous { 273022d268cbSEd Tanous return; 273122d268cbSEd Tanous } 273222d268cbSEd Tanous if (chassisId != "system") 273322d268cbSEd Tanous { 273422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 273522d268cbSEd Tanous return; 273622d268cbSEd Tanous } 273722d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 273822d268cbSEd Tanous } 2739fdd26906SClaire Weinan 2740fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2741fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2742fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2743fdd26906SClaire Weinan const std::string& dumpId) 2744fdd26906SClaire Weinan { 2745fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2746fdd26906SClaire Weinan { 2747fdd26906SClaire Weinan return; 2748fdd26906SClaire Weinan } 2749fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2750fdd26906SClaire Weinan } 2751fdd26906SClaire Weinan 275222d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 275322d268cbSEd Tanous crow::App& app, const crow::Request& req, 275422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 275522d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 275622d268cbSEd Tanous { 275722d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 275822d268cbSEd Tanous { 275922d268cbSEd Tanous return; 276022d268cbSEd Tanous } 276122d268cbSEd Tanous if (chassisId != "system") 276222d268cbSEd Tanous { 276322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 276422d268cbSEd Tanous return; 276522d268cbSEd Tanous } 276622d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 276722d268cbSEd Tanous } 276822d268cbSEd Tanous 2769fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2770fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2771fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2772fdd26906SClaire Weinan { 2773fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2774fdd26906SClaire Weinan { 2775fdd26906SClaire Weinan return; 2776fdd26906SClaire Weinan } 2777fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2778fdd26906SClaire Weinan } 2779fdd26906SClaire Weinan 278022d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 278122d268cbSEd Tanous crow::App& app, const crow::Request& req, 278222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 278322d268cbSEd Tanous const std::string& chassisId) 278422d268cbSEd Tanous { 278522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 278622d268cbSEd Tanous { 278722d268cbSEd Tanous return; 278822d268cbSEd Tanous } 278922d268cbSEd Tanous if (chassisId != "system") 279022d268cbSEd Tanous { 279122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 279222d268cbSEd Tanous return; 279322d268cbSEd Tanous } 279422d268cbSEd Tanous createDump(asyncResp, req, "System"); 279522d268cbSEd Tanous } 279622d268cbSEd Tanous 2797fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 2798fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2799fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2800fdd26906SClaire Weinan { 2801fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2802fdd26906SClaire Weinan { 2803fdd26906SClaire Weinan return; 2804fdd26906SClaire Weinan } 2805fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 2806fdd26906SClaire Weinan } 2807fdd26906SClaire Weinan 280822d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 280922d268cbSEd Tanous crow::App& app, const crow::Request& req, 281022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 281122d268cbSEd Tanous const std::string& chassisId) 281222d268cbSEd Tanous { 281322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 281422d268cbSEd Tanous { 281522d268cbSEd Tanous return; 281622d268cbSEd Tanous } 281722d268cbSEd Tanous if (chassisId != "system") 281822d268cbSEd Tanous { 281922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 282022d268cbSEd Tanous return; 282122d268cbSEd Tanous } 282222d268cbSEd Tanous clearDump(asyncResp, "System"); 282322d268cbSEd Tanous } 282422d268cbSEd Tanous 2825fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 2826fdd26906SClaire Weinan { 2827fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 2828fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2829fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2830fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 2831fdd26906SClaire Weinan } 2832fdd26906SClaire Weinan 2833fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 2834fdd26906SClaire Weinan { 2835fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 2836fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2837fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2838fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 2839c9bb6861Sraviteja-b } 2840c9bb6861Sraviteja-b 28417e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 2842c9bb6861Sraviteja-b { 28437e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28447e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2845ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 2846fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2847fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 2848fdd26906SClaire Weinan 28497e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 28507e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 2851ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2852fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2853fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 2854c9bb6861Sraviteja-b } 2855c9bb6861Sraviteja-b 28567e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 2857c9bb6861Sraviteja-b { 28580fda0f12SGeorge Liu BMCWEB_ROUTE( 28590fda0f12SGeorge Liu app, 28600fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2861ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 28627e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 2863fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 2864fdd26906SClaire Weinan std::ref(app), "BMC")); 2865a43be80fSAsmitha Karunanithi } 2866a43be80fSAsmitha Karunanithi 28677e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 286880319af1SAsmitha Karunanithi { 28690fda0f12SGeorge Liu BMCWEB_ROUTE( 28700fda0f12SGeorge Liu app, 28710fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 2872ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 2873fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2874fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 287545ca1b86SEd Tanous } 2876fdd26906SClaire Weinan 2877fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 2878fdd26906SClaire Weinan { 2879fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 2880fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 2881fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2882fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 2883fdd26906SClaire Weinan } 2884fdd26906SClaire Weinan 2885fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 2886fdd26906SClaire Weinan { 2887fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 2888fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 2889fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2890fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 2891fdd26906SClaire Weinan std::ref(app), "FaultLog")); 2892fdd26906SClaire Weinan } 2893fdd26906SClaire Weinan 2894fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 2895fdd26906SClaire Weinan { 2896fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2897fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2898fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 2899fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 2900fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 2901fdd26906SClaire Weinan 2902fdd26906SClaire Weinan BMCWEB_ROUTE(app, 2903fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 2904fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 2905fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 2906fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 2907fdd26906SClaire Weinan } 2908fdd26906SClaire Weinan 2909fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 2910fdd26906SClaire Weinan { 2911fdd26906SClaire Weinan BMCWEB_ROUTE( 2912fdd26906SClaire Weinan app, 2913fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 2914fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 2915fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 2916fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 29175cb1dd27SAsmitha Karunanithi } 29185cb1dd27SAsmitha Karunanithi 29197e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 29205cb1dd27SAsmitha Karunanithi { 292122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 2922ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 29236ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 292422d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 29255cb1dd27SAsmitha Karunanithi } 29265cb1dd27SAsmitha Karunanithi 29277e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 29287e860f15SJohn Edward Broadbent { 292922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 2930ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 293122d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 293222d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 293322d268cbSEd Tanous std::ref(app))); 29345cb1dd27SAsmitha Karunanithi } 29355cb1dd27SAsmitha Karunanithi 29367e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 29375cb1dd27SAsmitha Karunanithi { 29387e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 293922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2940ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 29416ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 294222d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 29438d1b46d7Szhanghch05 29447e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 294522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 2946ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 29476ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 294822d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 29495cb1dd27SAsmitha Karunanithi } 2950c9bb6861Sraviteja-b 29517e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 2952c9bb6861Sraviteja-b { 29530fda0f12SGeorge Liu BMCWEB_ROUTE( 29540fda0f12SGeorge Liu app, 295522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 2956ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 295722d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 295822d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 295922d268cbSEd Tanous std::ref(app))); 2960a43be80fSAsmitha Karunanithi } 2961a43be80fSAsmitha Karunanithi 29627e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 2963a43be80fSAsmitha Karunanithi { 29640fda0f12SGeorge Liu BMCWEB_ROUTE( 29650fda0f12SGeorge Liu app, 296622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 2967ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 29686ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 296922d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 2970013487e5Sraviteja-b } 2971013487e5Sraviteja-b 29727e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 29731da66f75SEd Tanous { 29743946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 29753946028dSAppaRao Puli // method for security reasons. 29761da66f75SEd Tanous /** 29771da66f75SEd Tanous * Functions triggers appropriate requests on DBus 29781da66f75SEd Tanous */ 297922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 2980ed398213SEd Tanous // This is incorrect, should be: 2981ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 2982432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 2983002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2984002d39b4SEd Tanous [&app](const crow::Request& req, 298522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 298622d268cbSEd Tanous const std::string& systemName) { 29873ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 298845ca1b86SEd Tanous { 298945ca1b86SEd Tanous return; 299045ca1b86SEd Tanous } 299122d268cbSEd Tanous if (systemName != "system") 299222d268cbSEd Tanous { 299322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 299422d268cbSEd Tanous systemName); 299522d268cbSEd Tanous return; 299622d268cbSEd Tanous } 299722d268cbSEd Tanous 29987e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 29997e860f15SJohn Edward Broadbent // SubRoute 30000f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3001424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3002e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 30038e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 30044f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 30054f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 30064f50ae4bSGunnar Mills asyncResp->res.jsonValue["Id"] = "Oem Crashdump"; 3007e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3008e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 30097c8c4058STejas Patil 30107c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 30112b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 30127c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 30137c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 30147c8c4058STejas Patil redfishDateTimeOffset.second; 30157c8c4058STejas Patil 30161476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 30171476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3018002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 30191476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3020002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 30211476687dSEd Tanous ["target"] = 30221476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 30237e860f15SJohn Edward Broadbent }); 30241da66f75SEd Tanous } 30251da66f75SEd Tanous 30267e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 30275b61b5e8SJason M. Bills { 30280fda0f12SGeorge Liu BMCWEB_ROUTE( 30290fda0f12SGeorge Liu app, 303022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3031ed398213SEd Tanous // This is incorrect, should be: 3032ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3033432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 30347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 303545ca1b86SEd Tanous [&app](const crow::Request& req, 303622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 303722d268cbSEd Tanous const std::string& systemName) { 30383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 303945ca1b86SEd Tanous { 304045ca1b86SEd Tanous return; 304145ca1b86SEd Tanous } 304222d268cbSEd Tanous if (systemName != "system") 304322d268cbSEd Tanous { 304422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 304522d268cbSEd Tanous systemName); 304622d268cbSEd Tanous return; 304722d268cbSEd Tanous } 30485b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 30495b61b5e8SJason M. Bills [asyncResp](const boost::system::error_code ec, 3050cb13a392SEd Tanous const std::string&) { 30515b61b5e8SJason M. Bills if (ec) 30525b61b5e8SJason M. Bills { 30535b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 30545b61b5e8SJason M. Bills return; 30555b61b5e8SJason M. Bills } 30565b61b5e8SJason M. Bills messages::success(asyncResp->res); 30575b61b5e8SJason M. Bills }, 3058002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 30597e860f15SJohn Edward Broadbent }); 30605b61b5e8SJason M. Bills } 30615b61b5e8SJason M. Bills 30628d1b46d7Szhanghch05 static void 30638d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30648d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3065e855dd28SJason M. Bills { 3066043a0536SJohnathan Mantey auto getStoredLogCallback = 3067b9d36b47SEd Tanous [asyncResp, logID, 3068b9d36b47SEd Tanous &logEntryJson](const boost::system::error_code ec, 3069b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3070e855dd28SJason M. Bills if (ec) 3071e855dd28SJason M. Bills { 3072e855dd28SJason M. Bills BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 30731ddcf01aSJason M. Bills if (ec.value() == 30741ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 30751ddcf01aSJason M. Bills { 3076002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 30771ddcf01aSJason M. Bills } 30781ddcf01aSJason M. Bills else 30791ddcf01aSJason M. Bills { 3080e855dd28SJason M. Bills messages::internalError(asyncResp->res); 30811ddcf01aSJason M. Bills } 3082e855dd28SJason M. Bills return; 3083e855dd28SJason M. Bills } 3084043a0536SJohnathan Mantey 3085043a0536SJohnathan Mantey std::string timestamp{}; 3086043a0536SJohnathan Mantey std::string filename{}; 3087043a0536SJohnathan Mantey std::string logfile{}; 30882c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3089043a0536SJohnathan Mantey 3090043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3091e855dd28SJason M. Bills { 30929db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3093e855dd28SJason M. Bills return; 3094e855dd28SJason M. Bills } 3095e855dd28SJason M. Bills 3096043a0536SJohnathan Mantey std::string crashdumpURI = 3097e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3098043a0536SJohnathan Mantey logID + "/" + filename; 309984afc48bSJason M. Bills nlohmann::json::object_t logEntry; 31009c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 310184afc48bSJason M. Bills logEntry["@odata.id"] = 310284afc48bSJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID; 310384afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 310484afc48bSJason M. Bills logEntry["Id"] = logID; 310584afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 310684afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 310784afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 310884afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 310984afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 31102b20ef6eSJason M. Bills 31112b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 31122b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 31132b20ef6eSJason M. Bills // directly 31142b20ef6eSJason M. Bills if (logEntryJson.is_array()) 31152b20ef6eSJason M. Bills { 31162b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 31172b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 31182b20ef6eSJason M. Bills logEntryJson.size(); 31192b20ef6eSJason M. Bills } 31202b20ef6eSJason M. Bills else 31212b20ef6eSJason M. Bills { 3122d405bb51SJason M. Bills logEntryJson.update(logEntry); 31232b20ef6eSJason M. Bills } 3124e855dd28SJason M. Bills }; 3125d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3126d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3127d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3128d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3129e855dd28SJason M. Bills } 3130e855dd28SJason M. Bills 31317e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 31321da66f75SEd Tanous { 31333946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 31343946028dSAppaRao Puli // method for security reasons. 31351da66f75SEd Tanous /** 31361da66f75SEd Tanous * Functions triggers appropriate requests on DBus 31371da66f75SEd Tanous */ 31387e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 313922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3140ed398213SEd Tanous // This is incorrect, should be. 3141ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3142432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3143002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3144002d39b4SEd Tanous [&app](const crow::Request& req, 314522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 314622d268cbSEd Tanous const std::string& systemName) { 31473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 314845ca1b86SEd Tanous { 314945ca1b86SEd Tanous return; 315045ca1b86SEd Tanous } 315122d268cbSEd Tanous if (systemName != "system") 315222d268cbSEd Tanous { 315322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 315422d268cbSEd Tanous systemName); 315522d268cbSEd Tanous return; 315622d268cbSEd Tanous } 315722d268cbSEd Tanous 31582b20ef6eSJason M. Bills crow::connections::systemBus->async_method_call( 31592b20ef6eSJason M. Bills [asyncResp](const boost::system::error_code ec, 31602b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 31611da66f75SEd Tanous if (ec) 31621da66f75SEd Tanous { 31631da66f75SEd Tanous if (ec.value() != 31641da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 31651da66f75SEd Tanous { 31661da66f75SEd Tanous BMCWEB_LOG_DEBUG << "failed to get entries ec: " 31671da66f75SEd Tanous << ec.message(); 3168f12894f8SJason M. Bills messages::internalError(asyncResp->res); 31691da66f75SEd Tanous return; 31701da66f75SEd Tanous } 31711da66f75SEd Tanous } 3172e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 31731da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 31740f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3175424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3176002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3177e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3178424c4176SJason M. Bills "Collection of Crashdump Entries"; 3179002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3180a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 31812b20ef6eSJason M. Bills 31822b20ef6eSJason M. Bills for (const std::string& path : resp) 31831da66f75SEd Tanous { 31842b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3185e855dd28SJason M. Bills // Get the log ID 31862b20ef6eSJason M. Bills std::string logID = objPath.filename(); 31872b20ef6eSJason M. Bills if (logID.empty()) 31881da66f75SEd Tanous { 3189e855dd28SJason M. Bills continue; 31901da66f75SEd Tanous } 3191e855dd28SJason M. Bills // Add the log entry to the array 31922b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 31932b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 31941da66f75SEd Tanous } 31952b20ef6eSJason M. Bills }, 31961da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", 31971da66f75SEd Tanous "/xyz/openbmc_project/object_mapper", 31981da66f75SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0, 31995b61b5e8SJason M. Bills std::array<const char*, 1>{crashdumpInterface}); 32007e860f15SJohn Edward Broadbent }); 32011da66f75SEd Tanous } 32021da66f75SEd Tanous 32037e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 32041da66f75SEd Tanous { 32053946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32063946028dSAppaRao Puli // method for security reasons. 32071da66f75SEd Tanous 32087e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 320922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3210ed398213SEd Tanous // this is incorrect, should be 3211ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3212432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32137e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 321445ca1b86SEd Tanous [&app](const crow::Request& req, 32157e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 321622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 32173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 321845ca1b86SEd Tanous { 321945ca1b86SEd Tanous return; 322045ca1b86SEd Tanous } 322122d268cbSEd Tanous if (systemName != "system") 322222d268cbSEd Tanous { 322322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 322422d268cbSEd Tanous systemName); 322522d268cbSEd Tanous return; 322622d268cbSEd Tanous } 32277e860f15SJohn Edward Broadbent const std::string& logID = param; 3228e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 32297e860f15SJohn Edward Broadbent }); 3230e855dd28SJason M. Bills } 3231e855dd28SJason M. Bills 32327e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3233e855dd28SJason M. Bills { 32343946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32353946028dSAppaRao Puli // method for security reasons. 32367e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 32377e860f15SJohn Edward Broadbent app, 323822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3239ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32407e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3241a4ce114aSNan Zhou [](const crow::Request& req, 32427e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324322d268cbSEd Tanous const std::string& systemName, const std::string& logID, 324422d268cbSEd Tanous const std::string& fileName) { 32452a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 32462a9beeedSShounak Mitra // Redfish resource. 324722d268cbSEd Tanous 324822d268cbSEd Tanous if (systemName != "system") 324922d268cbSEd Tanous { 325022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 325122d268cbSEd Tanous systemName); 325222d268cbSEd Tanous return; 325322d268cbSEd Tanous } 325422d268cbSEd Tanous 3255043a0536SJohnathan Mantey auto getStoredLogCallback = 3256002d39b4SEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))]( 3257abf2add6SEd Tanous const boost::system::error_code ec, 3258002d39b4SEd Tanous const std::vector< 3259002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 32607e860f15SJohn Edward Broadbent resp) { 32611da66f75SEd Tanous if (ec) 32621da66f75SEd Tanous { 3263002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); 3264f12894f8SJason M. Bills messages::internalError(asyncResp->res); 32651da66f75SEd Tanous return; 32661da66f75SEd Tanous } 3267e855dd28SJason M. Bills 3268043a0536SJohnathan Mantey std::string dbusFilename{}; 3269043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3270043a0536SJohnathan Mantey std::string dbusFilepath{}; 3271043a0536SJohnathan Mantey 3272002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3273002d39b4SEd Tanous dbusFilepath); 3274043a0536SJohnathan Mantey 3275043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3276043a0536SJohnathan Mantey dbusFilepath.empty()) 32771da66f75SEd Tanous { 32789db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 32791da66f75SEd Tanous return; 32801da66f75SEd Tanous } 3281e855dd28SJason M. Bills 3282043a0536SJohnathan Mantey // Verify the file name parameter is correct 3283043a0536SJohnathan Mantey if (fileName != dbusFilename) 3284043a0536SJohnathan Mantey { 32859db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3286043a0536SJohnathan Mantey return; 3287043a0536SJohnathan Mantey } 3288043a0536SJohnathan Mantey 3289043a0536SJohnathan Mantey if (!std::filesystem::exists(dbusFilepath)) 3290043a0536SJohnathan Mantey { 32919db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3292043a0536SJohnathan Mantey return; 3293043a0536SJohnathan Mantey } 3294002d39b4SEd Tanous std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary); 3295002d39b4SEd Tanous asyncResp->res.body() = 3296002d39b4SEd Tanous std::string(std::istreambuf_iterator<char>{ifs}, {}); 3297043a0536SJohnathan Mantey 32987e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 32997e860f15SJohn Edward Broadbent // from a browser 3300d9f6c621SEd Tanous asyncResp->res.addHeader( 3301d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 33021da66f75SEd Tanous }; 3303d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3304d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3305d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3306d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 33077e860f15SJohn Edward Broadbent }); 33081da66f75SEd Tanous } 33091da66f75SEd Tanous 3310c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3311c5a4c82aSJason M. Bills { 3312c5a4c82aSJason M. Bills onDemand, 3313c5a4c82aSJason M. Bills telemetry, 3314c5a4c82aSJason M. Bills invalid, 3315c5a4c82aSJason M. Bills }; 3316c5a4c82aSJason M. Bills 3317f7725d79SEd Tanous inline OEMDiagnosticType 3318f7725d79SEd Tanous getOEMDiagnosticType(const std::string_view& oemDiagStr) 3319c5a4c82aSJason M. Bills { 3320c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3321c5a4c82aSJason M. Bills { 3322c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3323c5a4c82aSJason M. Bills } 3324c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3325c5a4c82aSJason M. Bills { 3326c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3327c5a4c82aSJason M. Bills } 3328c5a4c82aSJason M. Bills 3329c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3330c5a4c82aSJason M. Bills } 3331c5a4c82aSJason M. Bills 33327e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 33331da66f75SEd Tanous { 33343946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 33353946028dSAppaRao Puli // method for security reasons. 33360fda0f12SGeorge Liu BMCWEB_ROUTE( 33370fda0f12SGeorge Liu app, 333822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3339ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3340ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3341432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3342002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3343002d39b4SEd Tanous [&app](const crow::Request& req, 334422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 334522d268cbSEd Tanous const std::string& systemName) { 33463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 334745ca1b86SEd Tanous { 334845ca1b86SEd Tanous return; 334945ca1b86SEd Tanous } 335022d268cbSEd Tanous 335122d268cbSEd Tanous if (systemName != "system") 335222d268cbSEd Tanous { 335322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 335422d268cbSEd Tanous systemName); 335522d268cbSEd Tanous return; 335622d268cbSEd Tanous } 335722d268cbSEd Tanous 33588e6c099aSJason M. Bills std::string diagnosticDataType; 33598e6c099aSJason M. Bills std::string oemDiagnosticDataType; 336015ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3361002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3362002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 33638e6c099aSJason M. Bills { 33648e6c099aSJason M. Bills return; 33658e6c099aSJason M. Bills } 33668e6c099aSJason M. Bills 33678e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 33688e6c099aSJason M. Bills { 33698e6c099aSJason M. Bills BMCWEB_LOG_ERROR 33708e6c099aSJason M. Bills << "Only OEM DiagnosticDataType supported for Crashdump"; 33718e6c099aSJason M. Bills messages::actionParameterValueFormatError( 33728e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 33738e6c099aSJason M. Bills "CollectDiagnosticData"); 33748e6c099aSJason M. Bills return; 33758e6c099aSJason M. Bills } 33768e6c099aSJason M. Bills 3377c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3378c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3379c5a4c82aSJason M. Bills 3380c5a4c82aSJason M. Bills std::string iface; 3381c5a4c82aSJason M. Bills std::string method; 3382c5a4c82aSJason M. Bills std::string taskMatchStr; 3383c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3384c5a4c82aSJason M. Bills { 3385c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3386c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3387c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3388c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3389c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3390c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3391c5a4c82aSJason M. Bills } 3392c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3393c5a4c82aSJason M. Bills { 3394c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3395c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3396c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3397c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3398c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3399c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3400c5a4c82aSJason M. Bills } 3401c5a4c82aSJason M. Bills else 3402c5a4c82aSJason M. Bills { 3403c5a4c82aSJason M. Bills BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: " 3404c5a4c82aSJason M. Bills << oemDiagnosticDataType; 3405c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3406002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3407002d39b4SEd Tanous "CollectDiagnosticData"); 3408c5a4c82aSJason M. Bills return; 3409c5a4c82aSJason M. Bills } 3410c5a4c82aSJason M. Bills 3411c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3412c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 3413c5a4c82aSJason M. Bills taskMatchStr](const boost::system::error_code ec, 341498be3e39SEd Tanous const std::string&) mutable { 34151da66f75SEd Tanous if (ec) 34161da66f75SEd Tanous { 3417002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 34181da66f75SEd Tanous { 3419f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 34201da66f75SEd Tanous } 34214363d3b2SJason M. Bills else if (ec.value() == 34224363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 34234363d3b2SJason M. Bills { 3424002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3425002d39b4SEd Tanous "60"); 34264363d3b2SJason M. Bills } 34271da66f75SEd Tanous else 34281da66f75SEd Tanous { 3429f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34301da66f75SEd Tanous } 34311da66f75SEd Tanous return; 34321da66f75SEd Tanous } 3433002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 343459d494eeSPatrick Williams [](boost::system::error_code err, sdbusplus::message_t&, 3435002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 343666afe4faSJames Feist if (!err) 343766afe4faSJames Feist { 3438002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3439e5d5006bSJames Feist std::to_string(taskData->index))); 3440831d6b09SJames Feist taskData->state = "Completed"; 344166afe4faSJames Feist } 344232898ceaSJames Feist return task::completed; 344366afe4faSJames Feist }, 3444c5a4c82aSJason M. Bills taskMatchStr); 3445c5a4c82aSJason M. Bills 344646229577SJames Feist task->startTimer(std::chrono::minutes(5)); 344746229577SJames Feist task->populateResp(asyncResp->res); 344898be3e39SEd Tanous task->payload.emplace(std::move(payload)); 34491da66f75SEd Tanous }; 34508e6c099aSJason M. Bills 34511da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3452002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3453002d39b4SEd Tanous iface, method); 34547e860f15SJohn Edward Broadbent }); 34556eda7685SKenny L. Ku } 34566eda7685SKenny L. Ku 3457cb92c03bSAndrew Geissler /** 3458cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3459cb92c03bSAndrew Geissler */ 34607e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3461cb92c03bSAndrew Geissler { 3462cb92c03bSAndrew Geissler /** 3463cb92c03bSAndrew Geissler * Function handles POST method request. 3464cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3465cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3466cb92c03bSAndrew Geissler */ 34677e860f15SJohn Edward Broadbent 34680fda0f12SGeorge Liu BMCWEB_ROUTE( 34690fda0f12SGeorge Liu app, 347022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3471ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 34727e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 347345ca1b86SEd Tanous [&app](const crow::Request& req, 347422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 347522d268cbSEd Tanous const std::string& systemName) { 34763ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 347745ca1b86SEd Tanous { 347845ca1b86SEd Tanous return; 347945ca1b86SEd Tanous } 348022d268cbSEd Tanous if (systemName != "system") 348122d268cbSEd Tanous { 348222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 348322d268cbSEd Tanous systemName); 348422d268cbSEd Tanous return; 348522d268cbSEd Tanous } 3486cb92c03bSAndrew Geissler BMCWEB_LOG_DEBUG << "Do delete all entries."; 3487cb92c03bSAndrew Geissler 3488cb92c03bSAndrew Geissler // Process response from Logging service. 3489002d39b4SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code ec) { 3490002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done"; 3491cb92c03bSAndrew Geissler if (ec) 3492cb92c03bSAndrew Geissler { 3493cb92c03bSAndrew Geissler // TODO Handle for specific error code 3494002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec; 3495cb92c03bSAndrew Geissler asyncResp->res.result( 3496cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3497cb92c03bSAndrew Geissler return; 3498cb92c03bSAndrew Geissler } 3499cb92c03bSAndrew Geissler 3500002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3501cb92c03bSAndrew Geissler }; 3502cb92c03bSAndrew Geissler 3503cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3504cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 35052c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3506cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3507cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35087e860f15SJohn Edward Broadbent }); 3509cb92c03bSAndrew Geissler } 3510a3316fc6SZhikuiRen 3511a3316fc6SZhikuiRen /**************************************************** 3512a3316fc6SZhikuiRen * Redfish PostCode interfaces 3513a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3514a3316fc6SZhikuiRen ******************************************************/ 35157e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3516a3316fc6SZhikuiRen { 351722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3518ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3519002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3520002d39b4SEd Tanous [&app](const crow::Request& req, 352122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352222d268cbSEd Tanous const std::string& systemName) { 35233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 352445ca1b86SEd Tanous { 352545ca1b86SEd Tanous return; 352645ca1b86SEd Tanous } 352722d268cbSEd Tanous if (systemName != "system") 352822d268cbSEd Tanous { 352922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 353022d268cbSEd Tanous systemName); 353122d268cbSEd Tanous return; 353222d268cbSEd Tanous } 35331476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 35341476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 35351476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 35361476687dSEd Tanous "#LogService.v1_1_0.LogService"; 35371476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 35381476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 35391476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log"; 35401476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 35411476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 35421476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 35437c8c4058STejas Patil 35447c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 35452b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 35460fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 35477c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 35487c8c4058STejas Patil redfishDateTimeOffset.second; 35497c8c4058STejas Patil 3550a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 35517e860f15SJohn Edward Broadbent {"target", 35520fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 35537e860f15SJohn Edward Broadbent }); 3554a3316fc6SZhikuiRen } 3555a3316fc6SZhikuiRen 35567e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3557a3316fc6SZhikuiRen { 35580fda0f12SGeorge Liu BMCWEB_ROUTE( 35590fda0f12SGeorge Liu app, 356022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3561ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3562ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3563432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35647e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 356545ca1b86SEd Tanous [&app](const crow::Request& req, 356622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 356722d268cbSEd Tanous const std::string& systemName) { 35683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 356945ca1b86SEd Tanous { 357045ca1b86SEd Tanous return; 357145ca1b86SEd Tanous } 357222d268cbSEd Tanous if (systemName != "system") 357322d268cbSEd Tanous { 357422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 357522d268cbSEd Tanous systemName); 357622d268cbSEd Tanous return; 357722d268cbSEd Tanous } 3578a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "Do delete all postcodes entries."; 3579a3316fc6SZhikuiRen 3580a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3581a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3582a3316fc6SZhikuiRen [asyncResp](const boost::system::error_code ec) { 3583a3316fc6SZhikuiRen if (ec) 3584a3316fc6SZhikuiRen { 3585a3316fc6SZhikuiRen // TODO Handle for specific error code 3586002d39b4SEd Tanous BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error " 35877e860f15SJohn Edward Broadbent << ec; 3588002d39b4SEd Tanous asyncResp->res.result( 3589002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3590a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3591a3316fc6SZhikuiRen return; 3592a3316fc6SZhikuiRen } 3593a3316fc6SZhikuiRen }, 359415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 359515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3596a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 35977e860f15SJohn Edward Broadbent }); 3598a3316fc6SZhikuiRen } 3599a3316fc6SZhikuiRen 36006f284d24SJiaqing Zhao /** 36016f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 36026f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 36036f284d24SJiaqing Zhao * 36046f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 36056f284d24SJiaqing Zhao * @param[out] currentValue Current value 36066f284d24SJiaqing Zhao * @param[out] index Index value 36076f284d24SJiaqing Zhao * 36086f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 36096f284d24SJiaqing Zhao */ 36106f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 36116f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 36126f284d24SJiaqing Zhao { 36136f284d24SJiaqing Zhao std::vector<std::string> split; 36146f284d24SJiaqing Zhao boost::algorithm::split(split, postCodeID, boost::is_any_of("-")); 36156f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 36166f284d24SJiaqing Zhao { 36176f284d24SJiaqing Zhao return false; 36186f284d24SJiaqing Zhao } 36196f284d24SJiaqing Zhao 36206f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36216f284d24SJiaqing Zhao const char* start = split[0].data() + 1; 36226f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36236f284d24SJiaqing Zhao const char* end = split[0].data() + split[0].size(); 36246f284d24SJiaqing Zhao auto [ptrIndex, ecIndex] = std::from_chars(start, end, index); 36256f284d24SJiaqing Zhao 36266f284d24SJiaqing Zhao if (ptrIndex != end || ecIndex != std::errc()) 36276f284d24SJiaqing Zhao { 36286f284d24SJiaqing Zhao return false; 36296f284d24SJiaqing Zhao } 36306f284d24SJiaqing Zhao 36316f284d24SJiaqing Zhao start = split[1].data(); 36326f284d24SJiaqing Zhao 36336f284d24SJiaqing Zhao // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 36346f284d24SJiaqing Zhao end = split[1].data() + split[1].size(); 36356f284d24SJiaqing Zhao auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue); 36366f284d24SJiaqing Zhao 36376f284d24SJiaqing Zhao return ptrValue == end && ecValue == std::errc(); 36386f284d24SJiaqing Zhao } 36396f284d24SJiaqing Zhao 36406f284d24SJiaqing Zhao static bool fillPostCodeEntry( 36418d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 36426c9a279eSManojkiran Eda const boost::container::flat_map< 36436c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3644a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3645a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3646a3316fc6SZhikuiRen { 3647a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3648fffb8c1fSEd Tanous const registries::Message* message = 3649fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3650a3316fc6SZhikuiRen 3651a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3652a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 36536c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 36546c9a279eSManojkiran Eda code : postcode) 3655a3316fc6SZhikuiRen { 3656a3316fc6SZhikuiRen currentCodeIndex++; 3657a3316fc6SZhikuiRen std::string postcodeEntryID = 3658a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3659a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3660a3316fc6SZhikuiRen 3661a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3662a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3663a3316fc6SZhikuiRen 3664a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3665a3316fc6SZhikuiRen { // already incremented 3666a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3667a3316fc6SZhikuiRen } 3668a3316fc6SZhikuiRen else 3669a3316fc6SZhikuiRen { 3670a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3671a3316fc6SZhikuiRen } 3672a3316fc6SZhikuiRen 3673a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3674a3316fc6SZhikuiRen // not fall between top and skip 3675a3316fc6SZhikuiRen if ((codeIndex == 0) && 3676a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3677a3316fc6SZhikuiRen { 3678a3316fc6SZhikuiRen continue; 3679a3316fc6SZhikuiRen } 3680a3316fc6SZhikuiRen 36814e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3682a3316fc6SZhikuiRen // currentIndex 3683a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3684a3316fc6SZhikuiRen { 3685a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3686a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3687a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3688a3316fc6SZhikuiRen continue; 3689a3316fc6SZhikuiRen } 3690a3316fc6SZhikuiRen 3691a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 3692a3316fc6SZhikuiRen // index 3693a3316fc6SZhikuiRen 3694a3316fc6SZhikuiRen // Get the Created time from the timestamp 3695a3316fc6SZhikuiRen std::string entryTimeStr; 36961d8782e7SNan Zhou entryTimeStr = 36972b82937eSEd Tanous redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000); 3698a3316fc6SZhikuiRen 3699a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 3700a3316fc6SZhikuiRen std::ostringstream hexCode; 3701a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 37026c9a279eSManojkiran Eda << std::get<0>(code.second); 3703a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 3704a3316fc6SZhikuiRen // Set Fixed -Point Notation 3705a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 3706a3316fc6SZhikuiRen // Set precision to 4 digits 3707a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 3708a3316fc6SZhikuiRen // Add double to stream 3709a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 3710a3316fc6SZhikuiRen std::vector<std::string> messageArgs = { 3711a3316fc6SZhikuiRen std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()}; 3712a3316fc6SZhikuiRen 3713a3316fc6SZhikuiRen // Get MessageArgs template from message registry 3714a3316fc6SZhikuiRen std::string msg; 3715a3316fc6SZhikuiRen if (message != nullptr) 3716a3316fc6SZhikuiRen { 3717a3316fc6SZhikuiRen msg = message->message; 3718a3316fc6SZhikuiRen 3719a3316fc6SZhikuiRen // fill in this post code value 3720a3316fc6SZhikuiRen int i = 0; 3721a3316fc6SZhikuiRen for (const std::string& messageArg : messageArgs) 3722a3316fc6SZhikuiRen { 3723a3316fc6SZhikuiRen std::string argStr = "%" + std::to_string(++i); 3724a3316fc6SZhikuiRen size_t argPos = msg.find(argStr); 3725a3316fc6SZhikuiRen if (argPos != std::string::npos) 3726a3316fc6SZhikuiRen { 3727a3316fc6SZhikuiRen msg.replace(argPos, argStr.length(), messageArg); 3728a3316fc6SZhikuiRen } 3729a3316fc6SZhikuiRen } 3730a3316fc6SZhikuiRen } 3731a3316fc6SZhikuiRen 3732d4342a92STim Lee // Get Severity template from message registry 3733d4342a92STim Lee std::string severity; 3734d4342a92STim Lee if (message != nullptr) 3735d4342a92STim Lee { 37365f2b84eeSEd Tanous severity = message->messageSeverity; 3737d4342a92STim Lee } 3738d4342a92STim Lee 37396f284d24SJiaqing Zhao // Format entry 37406f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 37419c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 374284afc48bSJason M. Bills bmcLogEntry["@odata.id"] = 37430fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 374484afc48bSJason M. Bills postcodeEntryID; 374584afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 374684afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 374784afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 374884afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 374984afc48bSJason M. Bills bmcLogEntry["MessageArgs"] = std::move(messageArgs); 375084afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 375184afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 375284afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 3753647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 3754647b3cdcSGeorge Liu { 3755647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 3756647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 3757647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 3758647b3cdcSGeorge Liu } 37596f284d24SJiaqing Zhao 37606f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 37616f284d24SJiaqing Zhao // that entry in this case 37626f284d24SJiaqing Zhao if (codeIndex != 0) 37636f284d24SJiaqing Zhao { 37646f284d24SJiaqing Zhao aResp->res.jsonValue.update(bmcLogEntry); 37656f284d24SJiaqing Zhao return true; 3766a3316fc6SZhikuiRen } 37676f284d24SJiaqing Zhao 37686f284d24SJiaqing Zhao nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"]; 37696f284d24SJiaqing Zhao logEntryArray.push_back(std::move(bmcLogEntry)); 37706f284d24SJiaqing Zhao } 37716f284d24SJiaqing Zhao 37726f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 37736f284d24SJiaqing Zhao return false; 3774a3316fc6SZhikuiRen } 3775a3316fc6SZhikuiRen 37768d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 37776f284d24SJiaqing Zhao const std::string& entryId) 3778a3316fc6SZhikuiRen { 37796f284d24SJiaqing Zhao uint16_t bootIndex = 0; 37806f284d24SJiaqing Zhao uint64_t codeIndex = 0; 37816f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 37826f284d24SJiaqing Zhao { 37836f284d24SJiaqing Zhao // Requested ID was not found 37846f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 37856f284d24SJiaqing Zhao return; 37866f284d24SJiaqing Zhao } 37876f284d24SJiaqing Zhao 37886f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 37896f284d24SJiaqing Zhao { 37906f284d24SJiaqing Zhao // 0 is an invalid index 37916f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 37926f284d24SJiaqing Zhao return; 37936f284d24SJiaqing Zhao } 37946f284d24SJiaqing Zhao 3795a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 37966f284d24SJiaqing Zhao [aResp, entryId, bootIndex, 37976c9a279eSManojkiran Eda codeIndex](const boost::system::error_code ec, 37986c9a279eSManojkiran Eda const boost::container::flat_map< 37996c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38006c9a279eSManojkiran Eda postcode) { 3801a3316fc6SZhikuiRen if (ec) 3802a3316fc6SZhikuiRen { 3803a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3804a3316fc6SZhikuiRen messages::internalError(aResp->res); 3805a3316fc6SZhikuiRen return; 3806a3316fc6SZhikuiRen } 3807a3316fc6SZhikuiRen 3808a3316fc6SZhikuiRen if (postcode.empty()) 3809a3316fc6SZhikuiRen { 38106f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 3811a3316fc6SZhikuiRen return; 3812a3316fc6SZhikuiRen } 3813a3316fc6SZhikuiRen 38146f284d24SJiaqing Zhao if (!fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex)) 38156f284d24SJiaqing Zhao { 38166f284d24SJiaqing Zhao messages::resourceNotFound(aResp->res, "LogEntry", entryId); 38176f284d24SJiaqing Zhao return; 38186f284d24SJiaqing Zhao } 3819a3316fc6SZhikuiRen }, 382015124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 382115124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3822a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3823a3316fc6SZhikuiRen bootIndex); 3824a3316fc6SZhikuiRen } 3825a3316fc6SZhikuiRen 38268d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 3827a3316fc6SZhikuiRen const uint16_t bootIndex, 3828a3316fc6SZhikuiRen const uint16_t bootCount, 38293648c8beSEd Tanous const uint64_t entryCount, size_t skip, 38303648c8beSEd Tanous size_t top) 3831a3316fc6SZhikuiRen { 3832a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 3833a3316fc6SZhikuiRen [aResp, bootIndex, bootCount, entryCount, skip, 3834a3316fc6SZhikuiRen top](const boost::system::error_code ec, 38356c9a279eSManojkiran Eda const boost::container::flat_map< 38366c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 38376c9a279eSManojkiran Eda postcode) { 3838a3316fc6SZhikuiRen if (ec) 3839a3316fc6SZhikuiRen { 3840a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error"; 3841a3316fc6SZhikuiRen messages::internalError(aResp->res); 3842a3316fc6SZhikuiRen return; 3843a3316fc6SZhikuiRen } 3844a3316fc6SZhikuiRen 3845a3316fc6SZhikuiRen uint64_t endCount = entryCount; 3846a3316fc6SZhikuiRen if (!postcode.empty()) 3847a3316fc6SZhikuiRen { 3848a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 38493648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 3850a3316fc6SZhikuiRen { 38513648c8beSEd Tanous uint64_t thisBootSkip = 38523648c8beSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) - 38533648c8beSEd Tanous entryCount; 3854a3316fc6SZhikuiRen uint64_t thisBootTop = 38553648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 38563648c8beSEd Tanous entryCount; 3857a3316fc6SZhikuiRen 3858002d39b4SEd Tanous fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip, 3859002d39b4SEd Tanous thisBootTop); 3860a3316fc6SZhikuiRen } 3861a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.count"] = endCount; 3862a3316fc6SZhikuiRen } 3863a3316fc6SZhikuiRen 3864a3316fc6SZhikuiRen // continue to previous bootIndex 3865a3316fc6SZhikuiRen if (bootIndex < bootCount) 3866a3316fc6SZhikuiRen { 3867a3316fc6SZhikuiRen getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1), 3868a3316fc6SZhikuiRen bootCount, endCount, skip, top); 3869a3316fc6SZhikuiRen } 387081584abeSJiaqing Zhao else if (skip + top < endCount) 3871a3316fc6SZhikuiRen { 3872a3316fc6SZhikuiRen aResp->res.jsonValue["Members@odata.nextLink"] = 38730fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 3874a3316fc6SZhikuiRen std::to_string(skip + top); 3875a3316fc6SZhikuiRen } 3876a3316fc6SZhikuiRen }, 387715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 387815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3879a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 3880a3316fc6SZhikuiRen bootIndex); 3881a3316fc6SZhikuiRen } 3882a3316fc6SZhikuiRen 38838d1b46d7Szhanghch05 static void 38848d1b46d7Szhanghch05 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 38853648c8beSEd Tanous size_t skip, size_t top) 3886a3316fc6SZhikuiRen { 3887a3316fc6SZhikuiRen uint64_t entryCount = 0; 38881e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 38891e1e598dSJonathan Doman *crow::connections::systemBus, 38901e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 38911e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 38921e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 38931e1e598dSJonathan Doman [aResp, entryCount, skip, top](const boost::system::error_code ec, 38941e1e598dSJonathan Doman const uint16_t bootCount) { 3895a3316fc6SZhikuiRen if (ec) 3896a3316fc6SZhikuiRen { 3897a3316fc6SZhikuiRen BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3898a3316fc6SZhikuiRen messages::internalError(aResp->res); 3899a3316fc6SZhikuiRen return; 3900a3316fc6SZhikuiRen } 39011e1e598dSJonathan Doman getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top); 39021e1e598dSJonathan Doman }); 3903a3316fc6SZhikuiRen } 3904a3316fc6SZhikuiRen 39057e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 3906a3316fc6SZhikuiRen { 39077e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 390822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 3909ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 39107e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 391145ca1b86SEd Tanous [&app](const crow::Request& req, 391222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 391322d268cbSEd Tanous const std::string& systemName) { 3914c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 3915c937d2bfSEd Tanous .canDelegateTop = true, 3916c937d2bfSEd Tanous .canDelegateSkip = true, 3917c937d2bfSEd Tanous }; 3918c937d2bfSEd Tanous query_param::Query delegatedQuery; 3919c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 39203ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 392145ca1b86SEd Tanous { 392245ca1b86SEd Tanous return; 392345ca1b86SEd Tanous } 392422d268cbSEd Tanous 392522d268cbSEd Tanous if (systemName != "system") 392622d268cbSEd Tanous { 392722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 392822d268cbSEd Tanous systemName); 392922d268cbSEd Tanous return; 393022d268cbSEd Tanous } 3931a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 3932a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 3933a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 3934a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 3935a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 3936a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 3937a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 3938a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3939a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 39403648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 39415143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 39423648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 39437e860f15SJohn Edward Broadbent }); 3944a3316fc6SZhikuiRen } 3945a3316fc6SZhikuiRen 3946647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 3947647b3cdcSGeorge Liu { 39480fda0f12SGeorge Liu BMCWEB_ROUTE( 39490fda0f12SGeorge Liu app, 395022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 3951647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 3952647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 395345ca1b86SEd Tanous [&app](const crow::Request& req, 3954647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 395522d268cbSEd Tanous const std::string& systemName, 3956647b3cdcSGeorge Liu const std::string& postCodeID) { 39573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 395845ca1b86SEd Tanous { 395945ca1b86SEd Tanous return; 396045ca1b86SEd Tanous } 396199351cd8SEd Tanous if (http_helpers::isContentTypeAllowed( 396299351cd8SEd Tanous req.getHeaderValue("Accept"), 39634a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 3964647b3cdcSGeorge Liu { 3965002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 3966647b3cdcSGeorge Liu return; 3967647b3cdcSGeorge Liu } 396822d268cbSEd Tanous if (systemName != "system") 396922d268cbSEd Tanous { 397022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 397122d268cbSEd Tanous systemName); 397222d268cbSEd Tanous return; 397322d268cbSEd Tanous } 3974647b3cdcSGeorge Liu 3975647b3cdcSGeorge Liu uint64_t currentValue = 0; 3976647b3cdcSGeorge Liu uint16_t index = 0; 3977647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 3978647b3cdcSGeorge Liu { 3979002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 3980647b3cdcSGeorge Liu return; 3981647b3cdcSGeorge Liu } 3982647b3cdcSGeorge Liu 3983647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 3984647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 3985647b3cdcSGeorge Liu const boost::system::error_code ec, 3986002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 3987002d39b4SEd Tanous postcodes) { 3988647b3cdcSGeorge Liu if (ec.value() == EBADR) 3989647b3cdcSGeorge Liu { 3990002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 3991002d39b4SEd Tanous postCodeID); 3992647b3cdcSGeorge Liu return; 3993647b3cdcSGeorge Liu } 3994647b3cdcSGeorge Liu if (ec) 3995647b3cdcSGeorge Liu { 3996647b3cdcSGeorge Liu BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 3997647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 3998647b3cdcSGeorge Liu return; 3999647b3cdcSGeorge Liu } 4000647b3cdcSGeorge Liu 4001647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4002002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4003647b3cdcSGeorge Liu { 4004647b3cdcSGeorge Liu BMCWEB_LOG_ERROR << "Wrong currentValue value"; 4005002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4006002d39b4SEd Tanous postCodeID); 4007647b3cdcSGeorge Liu return; 4008647b3cdcSGeorge Liu } 4009647b3cdcSGeorge Liu 40109eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 401146ff87baSEd Tanous if (c.empty()) 4012647b3cdcSGeorge Liu { 4013647b3cdcSGeorge Liu BMCWEB_LOG_INFO << "No found post code data"; 4014002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4015002d39b4SEd Tanous postCodeID); 4016647b3cdcSGeorge Liu return; 4017647b3cdcSGeorge Liu } 401846ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 401946ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 402046ff87baSEd Tanous std::string_view strData(d, c.size()); 4021647b3cdcSGeorge Liu 4022d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4023647b3cdcSGeorge Liu "application/octet-stream"); 4024d9f6c621SEd Tanous asyncResp->res.addHeader( 4025d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 4026002d39b4SEd Tanous asyncResp->res.body() = crow::utility::base64encode(strData); 4027647b3cdcSGeorge Liu }, 4028647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4029647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4030002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4031647b3cdcSGeorge Liu }); 4032647b3cdcSGeorge Liu } 4033647b3cdcSGeorge Liu 40347e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4035a3316fc6SZhikuiRen { 40367e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 403722d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4038ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 40397e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 404045ca1b86SEd Tanous [&app](const crow::Request& req, 40417e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 404222d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 40433ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 404445ca1b86SEd Tanous { 404545ca1b86SEd Tanous return; 404645ca1b86SEd Tanous } 404722d268cbSEd Tanous if (systemName != "system") 404822d268cbSEd Tanous { 404922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 405022d268cbSEd Tanous systemName); 405122d268cbSEd Tanous return; 405222d268cbSEd Tanous } 405322d268cbSEd Tanous 40546f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 40557e860f15SJohn Edward Broadbent }); 4056a3316fc6SZhikuiRen } 4057a3316fc6SZhikuiRen 40581da66f75SEd Tanous } // namespace redfish 4059