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 183ccb3adbSEd Tanous #include "app.hpp" 197a1dbc48SGeorge Liu #include "dbus_utility.hpp" 203ccb3adbSEd Tanous #include "error_messages.hpp" 2168dd075aSAsmitha Karunanithi #include "generated/enums/log_entry.hpp" 22b7028ebfSSpencer Ku #include "gzfile.hpp" 23647b3cdcSGeorge Liu #include "http_utility.hpp" 24b7028ebfSSpencer Ku #include "human_sort.hpp" 253ccb3adbSEd Tanous #include "query.hpp" 264851d45dSJason M. Bills #include "registries.hpp" 274851d45dSJason M. Bills #include "registries/base_message_registry.hpp" 284851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp" 293ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 3046229577SJames Feist #include "task.hpp" 313ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 323ccb3adbSEd Tanous #include "utils/time_utils.hpp" 331da66f75SEd Tanous 3475e8e218SMyung Bae #include <systemd/sd-id128.h> 35e1f26343SJason M. Bills #include <systemd/sd-journal.h> 368e31778eSAsmitha Karunanithi #include <tinyxml2.h> 37400fd1fbSAdriana Kobylak #include <unistd.h> 38e1f26343SJason M. Bills 3907c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 401da66f75SEd Tanous #include <boost/container/flat_map.hpp> 411ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 42ef4c65b7SEd Tanous #include <boost/url/format.hpp> 43d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 44d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 451214b7e7SGunnar Mills 467a1dbc48SGeorge Liu #include <array> 47647b3cdcSGeorge Liu #include <charconv> 48b5f288d2SAbhilash Raju #include <cstddef> 494418c7f0SJames Feist #include <filesystem> 5018f8f608SEd Tanous #include <iterator> 5175710de2SXiaochao Ma #include <optional> 523544d2a7SEd Tanous #include <ranges> 5326702d01SEd Tanous #include <span> 5418f8f608SEd Tanous #include <string> 55cd225da8SJason M. Bills #include <string_view> 56abf2add6SEd Tanous #include <variant> 571da66f75SEd Tanous 581da66f75SEd Tanous namespace redfish 591da66f75SEd Tanous { 601da66f75SEd Tanous 6189492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6289492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6389492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6489492a15SPatrick Williams constexpr const char* deleteAllInterface = 655b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6689492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 67424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6889492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 696eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 701da66f75SEd Tanous 718e31778eSAsmitha Karunanithi enum class DumpCreationProgress 728e31778eSAsmitha Karunanithi { 738e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 748e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 758e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 768e31778eSAsmitha Karunanithi }; 778e31778eSAsmitha Karunanithi 78f6150403SJames Feist namespace fs = std::filesystem; 791da66f75SEd Tanous 80cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 81cb92c03bSAndrew Geissler { 82d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 83d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 86cb92c03bSAndrew Geissler { 87cb92c03bSAndrew Geissler return "Critical"; 88cb92c03bSAndrew Geissler } 893174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 90d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 91d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 92cb92c03bSAndrew Geissler { 93cb92c03bSAndrew Geissler return "OK"; 94cb92c03bSAndrew Geissler } 953174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 96cb92c03bSAndrew Geissler { 97cb92c03bSAndrew Geissler return "Warning"; 98cb92c03bSAndrew Geissler } 99cb92c03bSAndrew Geissler return ""; 100cb92c03bSAndrew Geissler } 101cb92c03bSAndrew Geissler 1029017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1039017faf2SAbhishek Patel { 1049017faf2SAbhishek Patel std::optional<bool> notifyAction; 1059017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1069017faf2SAbhishek Patel { 1079017faf2SAbhishek Patel notifyAction = true; 1089017faf2SAbhishek Patel } 1099017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1109017faf2SAbhishek Patel { 1119017faf2SAbhishek Patel notifyAction = false; 1129017faf2SAbhishek Patel } 1139017faf2SAbhishek Patel 1149017faf2SAbhishek Patel return notifyAction; 1159017faf2SAbhishek Patel } 1169017faf2SAbhishek Patel 11718f8f608SEd Tanous inline std::string getDumpPath(std::string_view dumpType) 11818f8f608SEd Tanous { 11918f8f608SEd Tanous std::string dbusDumpPath = "/xyz/openbmc_project/dump/"; 12018f8f608SEd Tanous std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath), 12118f8f608SEd Tanous bmcweb::asciiToLower); 12218f8f608SEd Tanous 12318f8f608SEd Tanous return dbusDumpPath; 12418f8f608SEd Tanous } 12518f8f608SEd Tanous 126df254f2cSEd Tanous inline int getJournalMetadata(sd_journal* journal, std::string_view field, 12739e77504SEd Tanous std::string_view& contents) 12816428a1aSJason M. Bills { 12916428a1aSJason M. Bills const char* data = nullptr; 13016428a1aSJason M. Bills size_t length = 0; 13116428a1aSJason M. Bills int ret = 0; 13216428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 13346ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 13446ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 13546ff87baSEd Tanous 13646ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 13716428a1aSJason M. Bills if (ret < 0) 13816428a1aSJason M. Bills { 13916428a1aSJason M. Bills return ret; 14016428a1aSJason M. Bills } 14139e77504SEd Tanous contents = std::string_view(data, length); 14216428a1aSJason M. Bills // Only use the content after the "=" character. 14381ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 14416428a1aSJason M. Bills return ret; 14516428a1aSJason M. Bills } 14616428a1aSJason M. Bills 147df254f2cSEd Tanous inline int getJournalMetadata(sd_journal* journal, std::string_view field, 148df254f2cSEd Tanous const int& base, long int& contents) 14916428a1aSJason M. Bills { 15016428a1aSJason M. Bills int ret = 0; 15139e77504SEd Tanous std::string_view metadata; 15216428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 15316428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 15416428a1aSJason M. Bills if (ret < 0) 15516428a1aSJason M. Bills { 15616428a1aSJason M. Bills return ret; 15716428a1aSJason M. Bills } 158b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15916428a1aSJason M. Bills return ret; 16016428a1aSJason M. Bills } 16116428a1aSJason M. Bills 162df254f2cSEd Tanous inline bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp) 163a3316fc6SZhikuiRen { 164a3316fc6SZhikuiRen int ret = 0; 165a3316fc6SZhikuiRen uint64_t timestamp = 0; 166a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 167a3316fc6SZhikuiRen if (ret < 0) 168a3316fc6SZhikuiRen { 16962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 170a3316fc6SZhikuiRen return false; 171a3316fc6SZhikuiRen } 172e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1739c620e21SAsmitha Karunanithi return true; 174a3316fc6SZhikuiRen } 17550b8a43aSEd Tanous 176df254f2cSEd Tanous inline bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 177e85d6b16SJason M. Bills const bool firstEntry = true) 17816428a1aSJason M. Bills { 17916428a1aSJason M. Bills int ret = 0; 18075e8e218SMyung Bae static sd_id128_t prevBootID{}; 18116428a1aSJason M. Bills static uint64_t prevTs = 0; 18216428a1aSJason M. Bills static int index = 0; 183e85d6b16SJason M. Bills if (firstEntry) 184e85d6b16SJason M. Bills { 18575e8e218SMyung Bae prevBootID = {}; 186e85d6b16SJason M. Bills prevTs = 0; 187e85d6b16SJason M. Bills } 188e85d6b16SJason M. Bills 18916428a1aSJason M. Bills // Get the entry timestamp 19016428a1aSJason M. Bills uint64_t curTs = 0; 19175e8e218SMyung Bae sd_id128_t curBootID{}; 19275e8e218SMyung Bae ret = sd_journal_get_monotonic_usec(journal, &curTs, &curBootID); 19316428a1aSJason M. Bills if (ret < 0) 19416428a1aSJason M. Bills { 19562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 19616428a1aSJason M. Bills return false; 19716428a1aSJason M. Bills } 19875e8e218SMyung Bae // If the timestamp isn't unique on the same boot, increment the index 19975e8e218SMyung Bae bool sameBootIDs = sd_id128_equal(curBootID, prevBootID) != 0; 20075e8e218SMyung Bae if (sameBootIDs && (curTs == prevTs)) 20116428a1aSJason M. Bills { 20216428a1aSJason M. Bills index++; 20316428a1aSJason M. Bills } 20416428a1aSJason M. Bills else 20516428a1aSJason M. Bills { 20616428a1aSJason M. Bills // Otherwise, reset it 20716428a1aSJason M. Bills index = 0; 20816428a1aSJason M. Bills } 20975e8e218SMyung Bae 21075e8e218SMyung Bae if (!sameBootIDs) 21175e8e218SMyung Bae { 21275e8e218SMyung Bae // Save the bootID 21375e8e218SMyung Bae prevBootID = curBootID; 21475e8e218SMyung Bae } 21516428a1aSJason M. Bills // Save the timestamp 21616428a1aSJason M. Bills prevTs = curTs; 21716428a1aSJason M. Bills 21875e8e218SMyung Bae // make entryID as <bootID>_<timestamp>[_<index>] 21975e8e218SMyung Bae std::array<char, SD_ID128_STRING_MAX> bootIDStr{}; 22075e8e218SMyung Bae sd_id128_to_string(curBootID, bootIDStr.data()); 22175e8e218SMyung Bae entryID = std::format("{}_{}", bootIDStr.data(), curTs); 22216428a1aSJason M. Bills if (index > 0) 22316428a1aSJason M. Bills { 22416428a1aSJason M. Bills entryID += "_" + std::to_string(index); 22516428a1aSJason M. Bills } 22616428a1aSJason M. Bills return true; 22716428a1aSJason M. Bills } 22816428a1aSJason M. Bills 229e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 230e85d6b16SJason M. Bills const bool firstEntry = true) 23195820184SJason M. Bills { 232271584abSEd Tanous static time_t prevTs = 0; 23395820184SJason M. Bills static int index = 0; 234e85d6b16SJason M. Bills if (firstEntry) 235e85d6b16SJason M. Bills { 236e85d6b16SJason M. Bills prevTs = 0; 237e85d6b16SJason M. Bills } 238e85d6b16SJason M. Bills 23995820184SJason M. Bills // Get the entry timestamp 240271584abSEd Tanous std::time_t curTs = 0; 24195820184SJason M. Bills std::tm timeStruct = {}; 24295820184SJason M. Bills std::istringstream entryStream(logEntry); 24395820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 24495820184SJason M. Bills { 24595820184SJason M. Bills curTs = std::mktime(&timeStruct); 24695820184SJason M. Bills } 24795820184SJason M. Bills // If the timestamp isn't unique, increment the index 24895820184SJason M. Bills if (curTs == prevTs) 24995820184SJason M. Bills { 25095820184SJason M. Bills index++; 25195820184SJason M. Bills } 25295820184SJason M. Bills else 25395820184SJason M. Bills { 25495820184SJason M. Bills // Otherwise, reset it 25595820184SJason M. Bills index = 0; 25695820184SJason M. Bills } 25795820184SJason M. Bills // Save the timestamp 25895820184SJason M. Bills prevTs = curTs; 25995820184SJason M. Bills 26095820184SJason M. Bills entryID = std::to_string(curTs); 26195820184SJason M. Bills if (index > 0) 26295820184SJason M. Bills { 26395820184SJason M. Bills entryID += "_" + std::to_string(index); 26495820184SJason M. Bills } 26595820184SJason M. Bills return true; 26695820184SJason M. Bills } 26795820184SJason M. Bills 26875e8e218SMyung Bae // Entry is formed like "BootID_timestamp" or "BootID_timestamp_index" 269df254f2cSEd Tanous inline bool 2708d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 271099984c1SEd Tanous std::string_view entryIDStrView, sd_id128_t& bootID, 27275e8e218SMyung Bae uint64_t& timestamp, uint64_t& index) 27316428a1aSJason M. Bills { 27475e8e218SMyung Bae // Convert the unique ID back to a bootID + timestamp to find the entry 27575e8e218SMyung Bae auto underscore1Pos = entryIDStrView.find('_'); 27675e8e218SMyung Bae if (underscore1Pos == std::string_view::npos) 27775e8e218SMyung Bae { 27875e8e218SMyung Bae // EntryID has no bootID or timestamp 279099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 28075e8e218SMyung Bae return false; 28175e8e218SMyung Bae } 28275e8e218SMyung Bae 28375e8e218SMyung Bae // EntryID has bootID + timestamp 28475e8e218SMyung Bae 28575e8e218SMyung Bae // Convert entryIDViewString to BootID 28675e8e218SMyung Bae // NOTE: bootID string which needs to be null-terminated for 28775e8e218SMyung Bae // sd_id128_from_string() 288099984c1SEd Tanous std::string bootIDStr(entryIDStrView.substr(0, underscore1Pos)); 28975e8e218SMyung Bae if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0) 29075e8e218SMyung Bae { 291099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 29275e8e218SMyung Bae return false; 29375e8e218SMyung Bae } 29475e8e218SMyung Bae 29575e8e218SMyung Bae // Get the timestamp from entryID 296099984c1SEd Tanous entryIDStrView.remove_prefix(underscore1Pos + 1); 29775e8e218SMyung Bae 298099984c1SEd Tanous auto [timestampEnd, tstampEc] = std::from_chars( 299099984c1SEd Tanous entryIDStrView.begin(), entryIDStrView.end(), timestamp); 300099984c1SEd Tanous if (tstampEc != std::errc()) 30116428a1aSJason M. Bills { 302099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 30316428a1aSJason M. Bills return false; 30416428a1aSJason M. Bills } 305099984c1SEd Tanous entryIDStrView = std::string_view( 306099984c1SEd Tanous timestampEnd, 307099984c1SEd Tanous static_cast<size_t>(std::distance(timestampEnd, entryIDStrView.end()))); 308099984c1SEd Tanous if (entryIDStrView.empty()) 30916428a1aSJason M. Bills { 310099984c1SEd Tanous index = 0U; 311099984c1SEd Tanous return true; 312099984c1SEd Tanous } 313099984c1SEd Tanous // Timestamp might include optional index, if two events happened at the 314099984c1SEd Tanous // same "time". 315099984c1SEd Tanous if (entryIDStrView[0] != '_') 316099984c1SEd Tanous { 317099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 318099984c1SEd Tanous return false; 319099984c1SEd Tanous } 320099984c1SEd Tanous entryIDStrView.remove_prefix(1); 321099984c1SEd Tanous auto [ptr, indexEc] = std::from_chars(entryIDStrView.begin(), 322099984c1SEd Tanous entryIDStrView.end(), index); 323099984c1SEd Tanous if (indexEc != std::errc() || ptr != entryIDStrView.end()) 324099984c1SEd Tanous { 325099984c1SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView); 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 3513544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 35295820184SJason M. Bills 35395820184SJason M. Bills return !redfishLogFiles.empty(); 35495820184SJason M. Bills } 35595820184SJason M. Bills 35668dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 35768dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 35868dd075aSAsmitha Karunanithi { 35968dd075aSAsmitha Karunanithi if (originatorType == 36068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 36168dd075aSAsmitha Karunanithi { 36268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 36368dd075aSAsmitha Karunanithi } 36468dd075aSAsmitha Karunanithi if (originatorType == 36568dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 36668dd075aSAsmitha Karunanithi { 36768dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 36868dd075aSAsmitha Karunanithi } 36968dd075aSAsmitha Karunanithi if (originatorType == 37068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 37168dd075aSAsmitha Karunanithi { 37268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 37368dd075aSAsmitha Karunanithi } 37468dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 37568dd075aSAsmitha Karunanithi } 37668dd075aSAsmitha Karunanithi 377aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3782d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 379c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 38068dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 381aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 382aefe3786SClaire Weinan { 383aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 386aefe3786SClaire Weinan { 387aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 388aefe3786SClaire Weinan { 389aefe3786SClaire Weinan if (propertyMap.first == "Status") 390aefe3786SClaire Weinan { 391aefe3786SClaire Weinan const auto* status = 392aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 393aefe3786SClaire Weinan if (status == nullptr) 394aefe3786SClaire Weinan { 395aefe3786SClaire Weinan messages::internalError(asyncResp->res); 396aefe3786SClaire Weinan break; 397aefe3786SClaire Weinan } 398aefe3786SClaire Weinan dumpStatus = *status; 399aefe3786SClaire Weinan } 400aefe3786SClaire Weinan } 401aefe3786SClaire Weinan } 402aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 403aefe3786SClaire Weinan { 404aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 405aefe3786SClaire Weinan { 406aefe3786SClaire Weinan if (propertyMap.first == "Size") 407aefe3786SClaire Weinan { 408aefe3786SClaire Weinan const auto* sizePtr = 409aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 410aefe3786SClaire Weinan if (sizePtr == nullptr) 411aefe3786SClaire Weinan { 412aefe3786SClaire Weinan messages::internalError(asyncResp->res); 413aefe3786SClaire Weinan break; 414aefe3786SClaire Weinan } 415aefe3786SClaire Weinan size = *sizePtr; 416aefe3786SClaire Weinan break; 417aefe3786SClaire Weinan } 418aefe3786SClaire Weinan } 419aefe3786SClaire Weinan } 420aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 421aefe3786SClaire Weinan { 422aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 423aefe3786SClaire Weinan { 424aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 425aefe3786SClaire Weinan { 426aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 427aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 428aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 429aefe3786SClaire Weinan { 430aefe3786SClaire Weinan messages::internalError(asyncResp->res); 431aefe3786SClaire Weinan break; 432aefe3786SClaire Weinan } 433c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 434aefe3786SClaire Weinan break; 435aefe3786SClaire Weinan } 436aefe3786SClaire Weinan } 437aefe3786SClaire Weinan } 43868dd075aSAsmitha Karunanithi else if (interfaceMap.first == 43968dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 44068dd075aSAsmitha Karunanithi { 44168dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 44268dd075aSAsmitha Karunanithi { 44368dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 44468dd075aSAsmitha Karunanithi { 44568dd075aSAsmitha Karunanithi const std::string* id = 44668dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 44768dd075aSAsmitha Karunanithi if (id == nullptr) 44868dd075aSAsmitha Karunanithi { 44968dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 45068dd075aSAsmitha Karunanithi break; 45168dd075aSAsmitha Karunanithi } 45268dd075aSAsmitha Karunanithi originatorId = *id; 45368dd075aSAsmitha Karunanithi } 45468dd075aSAsmitha Karunanithi 45568dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 45668dd075aSAsmitha Karunanithi { 45768dd075aSAsmitha Karunanithi const std::string* type = 45868dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 45968dd075aSAsmitha Karunanithi if (type == nullptr) 46068dd075aSAsmitha Karunanithi { 46168dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46268dd075aSAsmitha Karunanithi break; 46368dd075aSAsmitha Karunanithi } 46468dd075aSAsmitha Karunanithi 46568dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 46668dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 46768dd075aSAsmitha Karunanithi { 46868dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46968dd075aSAsmitha Karunanithi break; 47068dd075aSAsmitha Karunanithi } 47168dd075aSAsmitha Karunanithi } 47268dd075aSAsmitha Karunanithi } 47368dd075aSAsmitha Karunanithi } 474aefe3786SClaire Weinan } 475aefe3786SClaire Weinan } 476aefe3786SClaire Weinan 47721ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 478fdd26906SClaire Weinan { 479fdd26906SClaire Weinan std::string entriesPath; 480fdd26906SClaire Weinan 481fdd26906SClaire Weinan if (dumpType == "BMC") 482fdd26906SClaire Weinan { 483fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 484fdd26906SClaire Weinan } 485fdd26906SClaire Weinan else if (dumpType == "FaultLog") 486fdd26906SClaire Weinan { 487fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 488fdd26906SClaire Weinan } 489fdd26906SClaire Weinan else if (dumpType == "System") 490fdd26906SClaire Weinan { 491fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 492fdd26906SClaire Weinan } 493fdd26906SClaire Weinan else 494fdd26906SClaire Weinan { 49562598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 49662598e31SEd Tanous dumpType); 497fdd26906SClaire Weinan } 498fdd26906SClaire Weinan 499fdd26906SClaire Weinan // Returns empty string on error 500fdd26906SClaire Weinan return entriesPath; 501fdd26906SClaire Weinan } 502fdd26906SClaire Weinan 5038d1b46d7Szhanghch05 inline void 5048d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5055cb1dd27SAsmitha Karunanithi const std::string& dumpType) 5065cb1dd27SAsmitha Karunanithi { 507fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 508fdd26906SClaire Weinan if (entriesPath.empty()) 5095cb1dd27SAsmitha Karunanithi { 5105cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5115cb1dd27SAsmitha Karunanithi return; 5125cb1dd27SAsmitha Karunanithi } 5135cb1dd27SAsmitha Karunanithi 5145eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5155eb468daSGeorge Liu dbus::utility::getManagedObjects( 5165eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 517fdd26906SClaire Weinan [asyncResp, entriesPath, 5185e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 5195eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 5205cb1dd27SAsmitha Karunanithi if (ec) 5215cb1dd27SAsmitha Karunanithi { 52262598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5235cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5245cb1dd27SAsmitha Karunanithi return; 5255cb1dd27SAsmitha Karunanithi } 5265cb1dd27SAsmitha Karunanithi 527fdd26906SClaire Weinan // Remove ending slash 528fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 529fdd26906SClaire Weinan if (!odataIdStr.empty()) 530fdd26906SClaire Weinan { 531fdd26906SClaire Weinan odataIdStr.pop_back(); 532fdd26906SClaire Weinan } 533fdd26906SClaire Weinan 534fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 535fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 536fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 537fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 53889492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 53989492a15SPatrick Williams " Dump Entries"; 540fdd26906SClaire Weinan 5413544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 54218f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 5435cb1dd27SAsmitha Karunanithi 5445eb468daSGeorge Liu dbus::utility::ManagedObjectType resp(objects); 5453544d2a7SEd Tanous std::ranges::sort(resp, [](const auto& l, const auto& r) { 546002d39b4SEd Tanous return AlphanumLess<std::string>()(l.first.filename(), 547002d39b4SEd Tanous r.first.filename()); 548565dfb6fSClaire Weinan }); 549565dfb6fSClaire Weinan 5505cb1dd27SAsmitha Karunanithi for (auto& object : resp) 5515cb1dd27SAsmitha Karunanithi { 552b47452b2SAsmitha Karunanithi if (object.first.str.find(dumpEntryPath) == std::string::npos) 5535cb1dd27SAsmitha Karunanithi { 5545cb1dd27SAsmitha Karunanithi continue; 5555cb1dd27SAsmitha Karunanithi } 556c6fecdabSClaire Weinan uint64_t timestampUs = 0; 5575cb1dd27SAsmitha Karunanithi uint64_t size = 0; 55835440d18SAsmitha Karunanithi std::string dumpStatus; 55968dd075aSAsmitha Karunanithi std::string originatorId; 56068dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 56168dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 562433b68b4SJason M. Bills nlohmann::json::object_t thisEntry; 5632dfd18efSEd Tanous 5642dfd18efSEd Tanous std::string entryID = object.first.filename(); 5652dfd18efSEd Tanous if (entryID.empty()) 5665cb1dd27SAsmitha Karunanithi { 5675cb1dd27SAsmitha Karunanithi continue; 5685cb1dd27SAsmitha Karunanithi } 5695cb1dd27SAsmitha Karunanithi 570c6fecdabSClaire Weinan parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs, 57168dd075aSAsmitha Karunanithi originatorId, originatorType, 572aefe3786SClaire Weinan asyncResp); 5735cb1dd27SAsmitha Karunanithi 5740fda0f12SGeorge Liu if (dumpStatus != 5750fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 57635440d18SAsmitha Karunanithi !dumpStatus.empty()) 57735440d18SAsmitha Karunanithi { 57835440d18SAsmitha Karunanithi // Dump status is not Complete, no need to enumerate 57935440d18SAsmitha Karunanithi continue; 58035440d18SAsmitha Karunanithi } 58135440d18SAsmitha Karunanithi 58268dd075aSAsmitha Karunanithi thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; 583fdd26906SClaire Weinan thisEntry["@odata.id"] = entriesPath + entryID; 5845cb1dd27SAsmitha Karunanithi thisEntry["Id"] = entryID; 5855cb1dd27SAsmitha Karunanithi thisEntry["EntryType"] = "Event"; 5865cb1dd27SAsmitha Karunanithi thisEntry["Name"] = dumpType + " Dump Entry"; 587bbd80db8SClaire Weinan thisEntry["Created"] = 588bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 5895cb1dd27SAsmitha Karunanithi 59068dd075aSAsmitha Karunanithi if (!originatorId.empty()) 59168dd075aSAsmitha Karunanithi { 59268dd075aSAsmitha Karunanithi thisEntry["Originator"] = originatorId; 59368dd075aSAsmitha Karunanithi thisEntry["OriginatorType"] = originatorType; 59468dd075aSAsmitha Karunanithi } 59568dd075aSAsmitha Karunanithi 5965cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 5975cb1dd27SAsmitha Karunanithi { 598d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "Manager"; 59989492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 60089492a15SPatrick Williams "/attachment"; 601fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6025cb1dd27SAsmitha Karunanithi } 6035cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6045cb1dd27SAsmitha Karunanithi { 605d337bb72SAsmitha Karunanithi thisEntry["DiagnosticDataType"] = "OEM"; 606d337bb72SAsmitha Karunanithi thisEntry["OEMDiagnosticDataType"] = "System"; 60789492a15SPatrick Williams thisEntry["AdditionalDataURI"] = entriesPath + entryID + 60889492a15SPatrick Williams "/attachment"; 609fdd26906SClaire Weinan thisEntry["AdditionalDataSizeBytes"] = size; 6105cb1dd27SAsmitha Karunanithi } 611b2ba3072SPatrick Williams entriesArray.emplace_back(std::move(thisEntry)); 6125cb1dd27SAsmitha Karunanithi } 613002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 6143544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 6155eb468daSGeorge Liu }); 6165cb1dd27SAsmitha Karunanithi } 6175cb1dd27SAsmitha Karunanithi 6188d1b46d7Szhanghch05 inline void 619c7a6d660SClaire Weinan getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6208d1b46d7Szhanghch05 const std::string& entryID, const std::string& dumpType) 6215cb1dd27SAsmitha Karunanithi { 622fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 623fdd26906SClaire Weinan if (entriesPath.empty()) 6245cb1dd27SAsmitha Karunanithi { 6255cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6265cb1dd27SAsmitha Karunanithi return; 6275cb1dd27SAsmitha Karunanithi } 6285cb1dd27SAsmitha Karunanithi 6295eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 6305eb468daSGeorge Liu dbus::utility::getManagedObjects( 6315eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 632fdd26906SClaire Weinan [asyncResp, entryID, dumpType, 6335e7e2dc5SEd Tanous entriesPath](const boost::system::error_code& ec, 63402cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 6355cb1dd27SAsmitha Karunanithi if (ec) 6365cb1dd27SAsmitha Karunanithi { 63762598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 6385cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 6395cb1dd27SAsmitha Karunanithi return; 6405cb1dd27SAsmitha Karunanithi } 6415cb1dd27SAsmitha Karunanithi 642b47452b2SAsmitha Karunanithi bool foundDumpEntry = false; 64318f8f608SEd Tanous std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/"; 644b47452b2SAsmitha Karunanithi 6459eb808c1SEd Tanous for (const auto& objectPath : resp) 6465cb1dd27SAsmitha Karunanithi { 647b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6485cb1dd27SAsmitha Karunanithi { 6495cb1dd27SAsmitha Karunanithi continue; 6505cb1dd27SAsmitha Karunanithi } 6515cb1dd27SAsmitha Karunanithi 6525cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 653c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6545cb1dd27SAsmitha Karunanithi uint64_t size = 0; 65535440d18SAsmitha Karunanithi std::string dumpStatus; 65668dd075aSAsmitha Karunanithi std::string originatorId; 65768dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 65868dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6595cb1dd27SAsmitha Karunanithi 660aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 66168dd075aSAsmitha Karunanithi timestampUs, originatorId, 66268dd075aSAsmitha Karunanithi originatorType, asyncResp); 6635cb1dd27SAsmitha Karunanithi 6640fda0f12SGeorge Liu if (dumpStatus != 6650fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 66635440d18SAsmitha Karunanithi !dumpStatus.empty()) 66735440d18SAsmitha Karunanithi { 66835440d18SAsmitha Karunanithi // Dump status is not Complete 66935440d18SAsmitha Karunanithi // return not found until status is changed to Completed 670d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 671d1bde9e5SKrzysztof Grobelny entryID); 67235440d18SAsmitha Karunanithi return; 67335440d18SAsmitha Karunanithi } 67435440d18SAsmitha Karunanithi 6755cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 67668dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 677fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6785cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6795cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6805cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 681bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 682bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6835cb1dd27SAsmitha Karunanithi 68468dd075aSAsmitha Karunanithi if (!originatorId.empty()) 68568dd075aSAsmitha Karunanithi { 68668dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 68768dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 68868dd075aSAsmitha Karunanithi } 68968dd075aSAsmitha Karunanithi 6905cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6915cb1dd27SAsmitha Karunanithi { 692d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 693d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 694fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 695fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6965cb1dd27SAsmitha Karunanithi } 6975cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 6985cb1dd27SAsmitha Karunanithi { 699d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 700002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 701d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 702fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 703fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7045cb1dd27SAsmitha Karunanithi } 7055cb1dd27SAsmitha Karunanithi } 706e05aec50SEd Tanous if (!foundDumpEntry) 707b47452b2SAsmitha Karunanithi { 70862598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 709b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 710b90d14f2SMyung Bae entryID); 711b47452b2SAsmitha Karunanithi return; 712b47452b2SAsmitha Karunanithi } 7135eb468daSGeorge Liu }); 7145cb1dd27SAsmitha Karunanithi } 7155cb1dd27SAsmitha Karunanithi 7168d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7179878256fSStanley Chu const std::string& entryID, 718b47452b2SAsmitha Karunanithi const std::string& dumpType) 7195cb1dd27SAsmitha Karunanithi { 7205a39f77aSPatrick Williams auto respHandler = [asyncResp, 7215a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 72262598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 7235cb1dd27SAsmitha Karunanithi if (ec) 7245cb1dd27SAsmitha Karunanithi { 7253de8d8baSGeorge Liu if (ec.value() == EBADR) 7263de8d8baSGeorge Liu { 7273de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 7283de8d8baSGeorge Liu return; 7293de8d8baSGeorge Liu } 73062598e31SEd Tanous BMCWEB_LOG_ERROR( 73162598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 73262598e31SEd Tanous entryID); 7335cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 7345cb1dd27SAsmitha Karunanithi return; 7355cb1dd27SAsmitha Karunanithi } 7365cb1dd27SAsmitha Karunanithi }; 73718f8f608SEd Tanous 7385cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7395cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 74018f8f608SEd Tanous std::format("{}/entry/{}", getDumpPath(dumpType), entryID), 7415cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7425cb1dd27SAsmitha Karunanithi } 743b5f288d2SAbhilash Raju inline bool checkSizeLimit(int fd, crow::Response& res) 744b5f288d2SAbhilash Raju { 745b5f288d2SAbhilash Raju long long int size = lseek(fd, 0, SEEK_END); 746b5f288d2SAbhilash Raju if (size <= 0) 747b5f288d2SAbhilash Raju { 748b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 749b5f288d2SAbhilash Raju size); 750b5f288d2SAbhilash Raju messages::internalError(res); 751b5f288d2SAbhilash Raju return false; 752b5f288d2SAbhilash Raju } 7535cb1dd27SAsmitha Karunanithi 754b5f288d2SAbhilash Raju // Arbitrary max size of 20MB to accommodate BMC dumps 755b5f288d2SAbhilash Raju constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 756b5f288d2SAbhilash Raju if (size > maxFileSize) 757b5f288d2SAbhilash Raju { 758b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 759b5f288d2SAbhilash Raju size, maxFileSize); 760b5f288d2SAbhilash Raju messages::internalError(res); 761b5f288d2SAbhilash Raju return false; 762b5f288d2SAbhilash Raju } 763b5f288d2SAbhilash Raju off_t rc = lseek(fd, 0, SEEK_SET); 764b5f288d2SAbhilash Raju if (rc < 0) 765b5f288d2SAbhilash Raju { 766b5f288d2SAbhilash Raju BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 767b5f288d2SAbhilash Raju messages::internalError(res); 768b5f288d2SAbhilash Raju return false; 769b5f288d2SAbhilash Raju } 770b5f288d2SAbhilash Raju return true; 771b5f288d2SAbhilash Raju } 772168d1b1aSCarson Labrado inline void 773168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 774168d1b1aSCarson Labrado const std::string& entryID, 775168d1b1aSCarson Labrado const std::string& downloadEntryType, 776168d1b1aSCarson Labrado const boost::system::error_code& ec, 777168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 778168d1b1aSCarson Labrado { 779168d1b1aSCarson Labrado if (ec.value() == EBADR) 780168d1b1aSCarson Labrado { 781168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 782168d1b1aSCarson Labrado return; 783168d1b1aSCarson Labrado } 784168d1b1aSCarson Labrado if (ec) 785168d1b1aSCarson Labrado { 786168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 787168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 788168d1b1aSCarson Labrado return; 789168d1b1aSCarson Labrado } 790168d1b1aSCarson Labrado 791168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 792168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 793168d1b1aSCarson Labrado { 794168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 795168d1b1aSCarson Labrado downloadEntryType); 796168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 797168d1b1aSCarson Labrado } 798168d1b1aSCarson Labrado 799168d1b1aSCarson Labrado int fd = -1; 800168d1b1aSCarson Labrado fd = dup(unixfd); 801168d1b1aSCarson Labrado if (fd < 0) 802168d1b1aSCarson Labrado { 803168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 804168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 805168d1b1aSCarson Labrado return; 806168d1b1aSCarson Labrado } 807b5f288d2SAbhilash Raju if (!checkSizeLimit(fd, asyncResp->res)) 808168d1b1aSCarson Labrado { 809168d1b1aSCarson Labrado close(fd); 810168d1b1aSCarson Labrado return; 811168d1b1aSCarson Labrado } 812168d1b1aSCarson Labrado if (downloadEntryType == "System") 813168d1b1aSCarson Labrado { 814b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 815b5f288d2SAbhilash Raju { 816b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 817b5f288d2SAbhilash Raju close(fd); 818b5f288d2SAbhilash Raju return; 819b5f288d2SAbhilash Raju } 820168d1b1aSCarson Labrado asyncResp->res.addHeader( 821168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 822b5f288d2SAbhilash Raju return; 823168d1b1aSCarson Labrado } 824b5f288d2SAbhilash Raju if (!asyncResp->res.openFd(fd)) 82527b0cf90SEd Tanous { 826b5f288d2SAbhilash Raju messages::internalError(asyncResp->res); 827b5f288d2SAbhilash Raju close(fd); 828b5f288d2SAbhilash Raju return; 82927b0cf90SEd Tanous } 830168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 831168d1b1aSCarson Labrado "application/octet-stream"); 832168d1b1aSCarson Labrado } 833168d1b1aSCarson Labrado 834168d1b1aSCarson Labrado inline void 835168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 836168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 837168d1b1aSCarson Labrado { 838168d1b1aSCarson Labrado if (dumpType != "BMC") 839168d1b1aSCarson Labrado { 840168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 841168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 842168d1b1aSCarson Labrado return; 843168d1b1aSCarson Labrado } 844168d1b1aSCarson Labrado 84518f8f608SEd Tanous std::string dumpEntryPath = std::format("{}/entry/{}", 84618f8f608SEd Tanous getDumpPath(dumpType), entryID); 847168d1b1aSCarson Labrado 848168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 849168d1b1aSCarson Labrado [asyncResp, entryID, 850168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 851168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 852168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 853168d1b1aSCarson Labrado }; 854168d1b1aSCarson Labrado 855168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 856168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 857168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 858168d1b1aSCarson Labrado } 859168d1b1aSCarson Labrado 860168d1b1aSCarson Labrado inline void 861168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 862168d1b1aSCarson Labrado const std::string& systemName, 863168d1b1aSCarson Labrado const std::string& entryID, 864168d1b1aSCarson Labrado const std::string& dumpType) 865168d1b1aSCarson Labrado { 866168d1b1aSCarson Labrado if constexpr (bmcwebEnableMultiHost) 867168d1b1aSCarson Labrado { 868168d1b1aSCarson Labrado // Option currently returns no systems. TBD 869168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 870168d1b1aSCarson Labrado systemName); 871168d1b1aSCarson Labrado return; 872168d1b1aSCarson Labrado } 873168d1b1aSCarson Labrado if (systemName != "system") 874168d1b1aSCarson Labrado { 875168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 876168d1b1aSCarson Labrado systemName); 877168d1b1aSCarson Labrado return; 878168d1b1aSCarson Labrado } 879168d1b1aSCarson Labrado 880168d1b1aSCarson Labrado std::string entryPath = 881168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 882168d1b1aSCarson Labrado entryID; 883168d1b1aSCarson Labrado 884168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 885168d1b1aSCarson Labrado [asyncResp, entryID, 886168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 887168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 888168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 889168d1b1aSCarson Labrado }; 890168d1b1aSCarson Labrado 891168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 892168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 893168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 894168d1b1aSCarson Labrado } 895168d1b1aSCarson Labrado 8968e31778eSAsmitha Karunanithi inline DumpCreationProgress 8978e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 898a43be80fSAsmitha Karunanithi { 8998e31778eSAsmitha Karunanithi if (status == 9008e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 9018e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 9028e31778eSAsmitha Karunanithi { 9038e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9048e31778eSAsmitha Karunanithi } 9058e31778eSAsmitha Karunanithi if (status == 9068e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 9078e31778eSAsmitha Karunanithi { 9088e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 9098e31778eSAsmitha Karunanithi } 9108e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9118e31778eSAsmitha Karunanithi } 9128e31778eSAsmitha Karunanithi 9138e31778eSAsmitha Karunanithi inline DumpCreationProgress 9148e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 9158e31778eSAsmitha Karunanithi { 9168e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 9178e31778eSAsmitha Karunanithi { 9188e31778eSAsmitha Karunanithi if (key == "Status") 9198e31778eSAsmitha Karunanithi { 9208e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 9218e31778eSAsmitha Karunanithi if (value == nullptr) 9228e31778eSAsmitha Karunanithi { 92362598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 9248e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9258e31778eSAsmitha Karunanithi } 9268e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 9278e31778eSAsmitha Karunanithi } 9288e31778eSAsmitha Karunanithi } 9298e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9308e31778eSAsmitha Karunanithi } 9318e31778eSAsmitha Karunanithi 9328e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 9338e31778eSAsmitha Karunanithi { 9348e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 9358e31778eSAsmitha Karunanithi { 9368e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 9378e31778eSAsmitha Karunanithi } 9388e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 9398e31778eSAsmitha Karunanithi { 9408e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 9418e31778eSAsmitha Karunanithi } 9428e31778eSAsmitha Karunanithi return ""; 9438e31778eSAsmitha Karunanithi } 9448e31778eSAsmitha Karunanithi 9458e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 9468e31778eSAsmitha Karunanithi task::Payload&& payload, 9478e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9488e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 9498e31778eSAsmitha Karunanithi { 9508e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 9518e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 9528e31778eSAsmitha Karunanithi 9538e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 9548e31778eSAsmitha Karunanithi 9558e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 9568e31778eSAsmitha Karunanithi { 95762598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 9588e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9598e31778eSAsmitha Karunanithi return; 9608e31778eSAsmitha Karunanithi } 9618e31778eSAsmitha Karunanithi 9628e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 963*8cb2c024SEd Tanous [asyncResp, payload = std::move(payload), createdObjPath, 9648e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 9655e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 9668e31778eSAsmitha Karunanithi const std::string& introspectXml) { 9678e31778eSAsmitha Karunanithi if (ec) 9688e31778eSAsmitha Karunanithi { 96962598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 97062598e31SEd Tanous ec.message()); 9718e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9728e31778eSAsmitha Karunanithi return; 9738e31778eSAsmitha Karunanithi } 9748e31778eSAsmitha Karunanithi 9758e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 9768e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 9778e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 9788e31778eSAsmitha Karunanithi // Else, return task completed. 9798e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 9808e31778eSAsmitha Karunanithi 9818e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 9828e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 9838e31778eSAsmitha Karunanithi if (pRoot == nullptr) 9848e31778eSAsmitha Karunanithi { 98562598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 9868e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9878e31778eSAsmitha Karunanithi return; 9888e31778eSAsmitha Karunanithi } 9898e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 9908e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 9918e31778eSAsmitha Karunanithi 9928e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 9938e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 9948e31778eSAsmitha Karunanithi { 9958e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 9968e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 9978e31778eSAsmitha Karunanithi { 9988e31778eSAsmitha Karunanithi if (thisInterfaceName == 9998e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 10008e31778eSAsmitha Karunanithi { 10018e31778eSAsmitha Karunanithi interfaceNode = 10028e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 10038e31778eSAsmitha Karunanithi continue; 10048e31778eSAsmitha Karunanithi } 10058e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 10068e31778eSAsmitha Karunanithi break; 10078e31778eSAsmitha Karunanithi } 10088e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 10098e31778eSAsmitha Karunanithi } 10108e31778eSAsmitha Karunanithi 1011a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 10128e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 10138b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 1014a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 10158b24275dSEd Tanous if (ec2) 1016cb13a392SEd Tanous { 101762598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 101862598e31SEd Tanous createdObjPath.str); 10198e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 10206145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 10216145ed6fSAsmitha Karunanithi return task::completed; 1022cb13a392SEd Tanous } 1023b9d36b47SEd Tanous 10248e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 1025a43be80fSAsmitha Karunanithi { 10268e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 10278e31778eSAsmitha Karunanithi std::string prop; 10288e31778eSAsmitha Karunanithi msg.read(prop, values); 10298e31778eSAsmitha Karunanithi 10308e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 10318e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 10328e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 10338e31778eSAsmitha Karunanithi { 103462598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 103562598e31SEd Tanous createdObjPath.str); 10368e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 10378e31778eSAsmitha Karunanithi return task::completed; 10388e31778eSAsmitha Karunanithi } 10398e31778eSAsmitha Karunanithi 10408e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 10418e31778eSAsmitha Karunanithi { 104262598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 104362598e31SEd Tanous createdObjPath.str); 10448e31778eSAsmitha Karunanithi return !task::completed; 10458e31778eSAsmitha Karunanithi } 10468e31778eSAsmitha Karunanithi } 10478e31778eSAsmitha Karunanithi 1048a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 1049a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 1050a43be80fSAsmitha Karunanithi 1051c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 1052c51a58eeSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId); 1053c51a58eeSEd Tanous 1054c51a58eeSEd Tanous std::string headerLoc = "Location: "; 1055c51a58eeSEd Tanous headerLoc += url.buffer(); 1056c51a58eeSEd Tanous 1057002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 1058a43be80fSAsmitha Karunanithi 105962598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 106062598e31SEd Tanous createdObjPath.str); 1061a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 1062b47452b2SAsmitha Karunanithi return task::completed; 1063a43be80fSAsmitha Karunanithi }, 10648e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 10658e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 10668e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 1067a43be80fSAsmitha Karunanithi 10688e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 10698e31778eSAsmitha Karunanithi // requested dump will be collected. 10708e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 1071a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 10728e31778eSAsmitha Karunanithi task->payload.emplace(payload); 10738e31778eSAsmitha Karunanithi }, 10748e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 10758e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 1076a43be80fSAsmitha Karunanithi } 1077a43be80fSAsmitha Karunanithi 10788d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10798d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 1080a43be80fSAsmitha Karunanithi { 1081fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 1082fdd26906SClaire Weinan if (dumpPath.empty()) 1083a43be80fSAsmitha Karunanithi { 1084a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1085a43be80fSAsmitha Karunanithi return; 1086a43be80fSAsmitha Karunanithi } 1087a43be80fSAsmitha Karunanithi 1088a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 1089a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 1090a43be80fSAsmitha Karunanithi 109115ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 1092a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 1093a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 1094a43be80fSAsmitha Karunanithi { 1095a43be80fSAsmitha Karunanithi return; 1096a43be80fSAsmitha Karunanithi } 1097a43be80fSAsmitha Karunanithi 1098a43be80fSAsmitha Karunanithi if (dumpType == "System") 1099a43be80fSAsmitha Karunanithi { 1100a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 1101a43be80fSAsmitha Karunanithi { 110262598e31SEd Tanous BMCWEB_LOG_ERROR( 110362598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 1104a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1105a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 1106a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 1107a43be80fSAsmitha Karunanithi return; 1108a43be80fSAsmitha Karunanithi } 11093174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 1110a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 1111a43be80fSAsmitha Karunanithi { 111262598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 1113ace85d60SEd Tanous messages::internalError(asyncResp->res); 1114a43be80fSAsmitha Karunanithi return; 1115a43be80fSAsmitha Karunanithi } 11165907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 1117a43be80fSAsmitha Karunanithi } 1118a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 1119a43be80fSAsmitha Karunanithi { 1120a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 1121a43be80fSAsmitha Karunanithi { 112262598e31SEd Tanous BMCWEB_LOG_ERROR( 112362598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 1124a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1125a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 1126a43be80fSAsmitha Karunanithi return; 1127a43be80fSAsmitha Karunanithi } 11283174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 1129a43be80fSAsmitha Karunanithi { 113062598e31SEd Tanous BMCWEB_LOG_ERROR( 113162598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 1132ace85d60SEd Tanous messages::internalError(asyncResp->res); 1133a43be80fSAsmitha Karunanithi return; 1134a43be80fSAsmitha Karunanithi } 11355907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 11365907571dSAsmitha Karunanithi } 11375907571dSAsmitha Karunanithi else 11385907571dSAsmitha Karunanithi { 113962598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 11405907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11415907571dSAsmitha Karunanithi return; 1142a43be80fSAsmitha Karunanithi } 1143a43be80fSAsmitha Karunanithi 11448e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 11458e31778eSAsmitha Karunanithi createDumpParamVec; 11468e31778eSAsmitha Karunanithi 1147f574a8e1SCarson Labrado if (req.session != nullptr) 1148f574a8e1SCarson Labrado { 114968dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 115068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 115168dd075aSAsmitha Karunanithi req.session->clientIp); 115268dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 115368dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 115468dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1155f574a8e1SCarson Labrado } 115668dd075aSAsmitha Karunanithi 1157a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 11585e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 11595e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 11605e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 11618e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1162a43be80fSAsmitha Karunanithi if (ec) 1163a43be80fSAsmitha Karunanithi { 116462598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 11655907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 11665907571dSAsmitha Karunanithi if (dbusError == nullptr) 11675907571dSAsmitha Karunanithi { 11685907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11695907571dSAsmitha Karunanithi return; 11705907571dSAsmitha Karunanithi } 11715907571dSAsmitha Karunanithi 117262598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 117362598e31SEd Tanous dbusError->name, dbusError->message); 11745907571dSAsmitha Karunanithi if (std::string_view( 11755907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 11765907571dSAsmitha Karunanithi dbusError->name) 11775907571dSAsmitha Karunanithi { 11785907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 11795907571dSAsmitha Karunanithi return; 11805907571dSAsmitha Karunanithi } 11815907571dSAsmitha Karunanithi if (std::string_view( 11825907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 11835907571dSAsmitha Karunanithi dbusError->name) 11845907571dSAsmitha Karunanithi { 11855907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 11865907571dSAsmitha Karunanithi return; 11875907571dSAsmitha Karunanithi } 11885907571dSAsmitha Karunanithi if (std::string_view( 11895907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 11905907571dSAsmitha Karunanithi dbusError->name) 11915907571dSAsmitha Karunanithi { 11925907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 11935907571dSAsmitha Karunanithi return; 11945907571dSAsmitha Karunanithi } 11955907571dSAsmitha Karunanithi // Other Dbus errors such as: 11965907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 11975907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 11985907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 11995907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 12005907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 12015907571dSAsmitha Karunanithi // back to the client. 1202a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1203a43be80fSAsmitha Karunanithi return; 1204a43be80fSAsmitha Karunanithi } 120562598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 12068e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1207a43be80fSAsmitha Karunanithi }, 120818f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12098e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1210a43be80fSAsmitha Karunanithi } 1211a43be80fSAsmitha Karunanithi 12128d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12138d1b46d7Szhanghch05 const std::string& dumpType) 121480319af1SAsmitha Karunanithi { 12150d946211SClaire Weinan crow::connections::systemBus->async_method_call( 12160d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 121780319af1SAsmitha Karunanithi if (ec) 121880319af1SAsmitha Karunanithi { 121962598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 122080319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 122180319af1SAsmitha Karunanithi return; 122280319af1SAsmitha Karunanithi } 12230d946211SClaire Weinan }, 122418f8f608SEd Tanous "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType), 12250d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 122680319af1SAsmitha Karunanithi } 122780319af1SAsmitha Karunanithi 1228df254f2cSEd Tanous inline void 1229b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1230b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1231b9d36b47SEd Tanous std::string& logfile) 1232043a0536SJohnathan Mantey { 1233d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1234d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1235d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1236d1bde9e5SKrzysztof Grobelny 1237d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1238d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1239d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1240d1bde9e5SKrzysztof Grobelny 1241d1bde9e5SKrzysztof Grobelny if (!success) 1242043a0536SJohnathan Mantey { 1243d1bde9e5SKrzysztof Grobelny return; 1244043a0536SJohnathan Mantey } 1245d1bde9e5SKrzysztof Grobelny 1246d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1247043a0536SJohnathan Mantey { 1248d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1249d1bde9e5SKrzysztof Grobelny } 1250d1bde9e5SKrzysztof Grobelny 1251d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1252043a0536SJohnathan Mantey { 1253d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1254043a0536SJohnathan Mantey } 1255d1bde9e5SKrzysztof Grobelny 1256d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1257043a0536SJohnathan Mantey { 1258d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1259043a0536SJohnathan Mantey } 1260043a0536SJohnathan Mantey } 1261043a0536SJohnathan Mantey 12627e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 12631da66f75SEd Tanous { 1264c4bf6374SJason M. Bills /** 1265c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1266c4bf6374SJason M. Bills */ 126722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1268ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1269002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1270002d39b4SEd Tanous [&app](const crow::Request& req, 127122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 127222d268cbSEd Tanous const std::string& systemName) { 12733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1274c4bf6374SJason M. Bills { 127545ca1b86SEd Tanous return; 127645ca1b86SEd Tanous } 12777f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 12787f3e84a1SEd Tanous { 12797f3e84a1SEd Tanous // Option currently returns no systems. TBD 12807f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 12817f3e84a1SEd Tanous systemName); 12827f3e84a1SEd Tanous return; 12837f3e84a1SEd Tanous } 128422d268cbSEd Tanous if (systemName != "system") 128522d268cbSEd Tanous { 128622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 128722d268cbSEd Tanous systemName); 128822d268cbSEd Tanous return; 128922d268cbSEd Tanous } 129022d268cbSEd Tanous 12917e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 12927e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1293c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1294c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1295c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1296029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 129745ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1298c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1299c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1300002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1301c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 13021476687dSEd Tanous nlohmann::json::object_t eventLog; 13031476687dSEd Tanous eventLog["@odata.id"] = 13041476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1305b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 13065cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 13071476687dSEd Tanous nlohmann::json::object_t dumpLog; 1308002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1309b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1310c9bb6861Sraviteja-b #endif 1311c9bb6861Sraviteja-b 1312d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 13131476687dSEd Tanous nlohmann::json::object_t crashdump; 13141476687dSEd Tanous crashdump["@odata.id"] = 13151476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1316b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1317d53dd41fSJason M. Bills #endif 1318b7028ebfSSpencer Ku 1319b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 13201476687dSEd Tanous nlohmann::json::object_t hostlogger; 13211476687dSEd Tanous hostlogger["@odata.id"] = 13221476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1323b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1324b7028ebfSSpencer Ku #endif 1325c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1326c4bf6374SJason M. Bills logServiceArray.size(); 1327a3316fc6SZhikuiRen 13287a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 13297a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 13307a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 13317a1dbc48SGeorge Liu "/", 0, interfaces, 13327a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1333b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1334b9d36b47SEd Tanous subtreePath) { 1335a3316fc6SZhikuiRen if (ec) 1336a3316fc6SZhikuiRen { 133762598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1338a3316fc6SZhikuiRen return; 1339a3316fc6SZhikuiRen } 1340a3316fc6SZhikuiRen 134155f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1342a3316fc6SZhikuiRen { 1343a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1344a3316fc6SZhikuiRen { 134523a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1346a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1347613dabeaSEd Tanous nlohmann::json::object_t member; 1348613dabeaSEd Tanous member["@odata.id"] = 1349613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1350613dabeaSEd Tanous 1351b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1352613dabeaSEd Tanous 135345ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 135423a21a1cSEd Tanous logServiceArrayLocal.size(); 1355a3316fc6SZhikuiRen return; 1356a3316fc6SZhikuiRen } 1357a3316fc6SZhikuiRen } 13587a1dbc48SGeorge Liu }); 13597e860f15SJohn Edward Broadbent }); 1360c4bf6374SJason M. Bills } 1361c4bf6374SJason M. Bills 13627e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1363c4bf6374SJason M. Bills { 136422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1365ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1366002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1367002d39b4SEd Tanous [&app](const crow::Request& req, 136822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 136922d268cbSEd Tanous const std::string& systemName) { 13703ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 137145ca1b86SEd Tanous { 137245ca1b86SEd Tanous return; 137345ca1b86SEd Tanous } 137422d268cbSEd Tanous if (systemName != "system") 137522d268cbSEd Tanous { 137622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 137722d268cbSEd Tanous systemName); 137822d268cbSEd Tanous return; 137922d268cbSEd Tanous } 1380c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1381029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1382c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1383b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1384c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1385002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1386c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1387c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 13887c8c4058STejas Patil 13897c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 13902b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 13917c8c4058STejas Patil 13927c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 13937c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 13947c8c4058STejas Patil redfishDateTimeOffset.second; 13957c8c4058STejas Patil 13961476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 13971476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1398e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1399e7d6c8b2SGunnar Mills 14000fda0f12SGeorge Liu {"target", 14010fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 14027e860f15SJohn Edward Broadbent }); 1403489640c6SJason M. Bills } 1404489640c6SJason M. Bills 14057e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1406489640c6SJason M. Bills { 14074978b63fSJason M. Bills BMCWEB_ROUTE( 14084978b63fSJason M. Bills app, 140922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1410432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 14117e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 141245ca1b86SEd Tanous [&app](const crow::Request& req, 141322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 141422d268cbSEd Tanous const std::string& systemName) { 14153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 141645ca1b86SEd Tanous { 141745ca1b86SEd Tanous return; 141845ca1b86SEd Tanous } 141922d268cbSEd Tanous if (systemName != "system") 142022d268cbSEd Tanous { 142122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 142222d268cbSEd Tanous systemName); 142322d268cbSEd Tanous return; 142422d268cbSEd Tanous } 1425489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1426489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1427489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1428489640c6SJason M. Bills { 1429489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1430489640c6SJason M. Bills { 1431489640c6SJason M. Bills std::error_code ec; 1432489640c6SJason M. Bills std::filesystem::remove(file, ec); 1433489640c6SJason M. Bills } 1434489640c6SJason M. Bills } 1435489640c6SJason M. Bills 1436489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1437489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 14385e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1439489640c6SJason M. Bills if (ec) 1440489640c6SJason M. Bills { 144162598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1442489640c6SJason M. Bills messages::internalError(asyncResp->res); 1443489640c6SJason M. Bills return; 1444489640c6SJason M. Bills } 1445489640c6SJason M. Bills 1446489640c6SJason M. Bills messages::success(asyncResp->res); 1447489640c6SJason M. Bills }, 1448489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1449002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1450002d39b4SEd Tanous "replace"); 14517e860f15SJohn Edward Broadbent }); 1452c4bf6374SJason M. Bills } 1453c4bf6374SJason M. Bills 1454ac992cdeSJason M. Bills enum class LogParseError 1455ac992cdeSJason M. Bills { 1456ac992cdeSJason M. Bills success, 1457ac992cdeSJason M. Bills parseFailed, 1458ac992cdeSJason M. Bills messageIdNotInRegistry, 1459ac992cdeSJason M. Bills }; 1460ac992cdeSJason M. Bills 1461ac992cdeSJason M. Bills static LogParseError 1462ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1463b5a76932SEd Tanous const std::string& logEntry, 1464de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1465c4bf6374SJason M. Bills { 146695820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1467cd225da8SJason M. Bills // First get the Timestamp 1468f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1469cd225da8SJason M. Bills if (space == std::string::npos) 147095820184SJason M. Bills { 1471ac992cdeSJason M. Bills return LogParseError::parseFailed; 147295820184SJason M. Bills } 1473cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1474cd225da8SJason M. Bills // Then get the log contents 1475f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1476cd225da8SJason M. Bills if (entryStart == std::string::npos) 1477cd225da8SJason M. Bills { 1478ac992cdeSJason M. Bills return LogParseError::parseFailed; 1479cd225da8SJason M. Bills } 1480cd225da8SJason M. Bills std::string_view entry(logEntry); 1481cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1482cd225da8SJason M. Bills // Use split to separate the entry into its fields 1483cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 148450ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1485cd225da8SJason M. Bills // We need at least a MessageId to be valid 14861e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 14871e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1488cd225da8SJason M. Bills { 1489ac992cdeSJason M. Bills return LogParseError::parseFailed; 1490cd225da8SJason M. Bills } 14911e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 14924851d45dSJason M. Bills // Get the Message from the MessageRegistry 1493fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1494c4bf6374SJason M. Bills 14951e6deaf6SEd Tanous logEntryIter++; 149654417b02SSui Chen if (message == nullptr) 1497c4bf6374SJason M. Bills { 149862598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1499ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1500c4bf6374SJason M. Bills } 1501c4bf6374SJason M. Bills 15021e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 15031e6deaf6SEd Tanous logEntryFields.end()); 1504c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1505c05bba45SEd Tanous 15061e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 15071e6deaf6SEd Tanous message->message); 15081e6deaf6SEd Tanous if (msg.empty()) 150915a86ff6SJason M. Bills { 15101e6deaf6SEd Tanous return LogParseError::parseFailed; 151115a86ff6SJason M. Bills } 15124851d45dSJason M. Bills 151395820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 151495820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 151595820184SJason M. Bills // between the '.' and the '+', so just remove them. 1516f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1517f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 151895820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1519c4bf6374SJason M. Bills { 152095820184SJason M. Bills timestamp.erase(dot, plus - dot); 1521c4bf6374SJason M. Bills } 1522c4bf6374SJason M. Bills 1523c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 15249c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1525ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1526ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1527ef4c65b7SEd Tanous logEntryID); 152884afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 152984afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 153084afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 153184afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 153284afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 153384afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 153484afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 153584afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1536ac992cdeSJason M. Bills return LogParseError::success; 1537c4bf6374SJason M. Bills } 1538c4bf6374SJason M. Bills 15397e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1540c4bf6374SJason M. Bills { 154122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 15428b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1543002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1544002d39b4SEd Tanous [&app](const crow::Request& req, 154522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 154622d268cbSEd Tanous const std::string& systemName) { 1547c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1548c937d2bfSEd Tanous .canDelegateTop = true, 1549c937d2bfSEd Tanous .canDelegateSkip = true, 1550c937d2bfSEd Tanous }; 1551c937d2bfSEd Tanous query_param::Query delegatedQuery; 1552c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 15533ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1554c4bf6374SJason M. Bills { 1555c4bf6374SJason M. Bills return; 1556c4bf6374SJason M. Bills } 15577f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 15587f3e84a1SEd Tanous { 15597f3e84a1SEd Tanous // Option currently returns no systems. TBD 15607f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15617f3e84a1SEd Tanous systemName); 15627f3e84a1SEd Tanous return; 15637f3e84a1SEd Tanous } 156422d268cbSEd Tanous if (systemName != "system") 156522d268cbSEd Tanous { 156622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 156722d268cbSEd Tanous systemName); 156822d268cbSEd Tanous return; 156922d268cbSEd Tanous } 157022d268cbSEd Tanous 15715143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15723648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 15733648c8beSEd Tanous 15747e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15757e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1576c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1577c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1578c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1579029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1580c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1581c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1582c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1583cb92c03bSAndrew Geissler 15844978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1585c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 15867e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 15877e860f15SJohn Edward Broadbent // entry 158895820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 158995820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1590b01bf299SEd Tanous uint64_t entryCount = 0; 1591cd225da8SJason M. Bills std::string logEntry; 159295820184SJason M. Bills 15937e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 15947e860f15SJohn Edward Broadbent // backwards 1595002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1596002d39b4SEd Tanous it++) 1597c4bf6374SJason M. Bills { 1598cd225da8SJason M. Bills std::ifstream logStream(*it); 159995820184SJason M. Bills if (!logStream.is_open()) 1600c4bf6374SJason M. Bills { 1601c4bf6374SJason M. Bills continue; 1602c4bf6374SJason M. Bills } 1603c4bf6374SJason M. Bills 1604e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1605e85d6b16SJason M. Bills bool firstEntry = true; 160695820184SJason M. Bills while (std::getline(logStream, logEntry)) 160795820184SJason M. Bills { 1608c4bf6374SJason M. Bills std::string idStr; 1609e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1610c4bf6374SJason M. Bills { 1611c4bf6374SJason M. Bills continue; 1612c4bf6374SJason M. Bills } 1613e85d6b16SJason M. Bills firstEntry = false; 1614e85d6b16SJason M. Bills 1615de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 161689492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 161789492a15SPatrick Williams bmcLogEntry); 1618ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1619ac992cdeSJason M. Bills { 1620ac992cdeSJason M. Bills continue; 1621ac992cdeSJason M. Bills } 1622ac992cdeSJason M. Bills if (status != LogParseError::success) 1623c4bf6374SJason M. Bills { 1624c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1625c4bf6374SJason M. Bills return; 1626c4bf6374SJason M. Bills } 1627de703c5dSJason M. Bills 1628de703c5dSJason M. Bills entryCount++; 1629de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1630de703c5dSJason M. Bills // start) and top (number of entries to display) 16313648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1632de703c5dSJason M. Bills { 1633de703c5dSJason M. Bills continue; 1634de703c5dSJason M. Bills } 1635de703c5dSJason M. Bills 1636b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1637c4bf6374SJason M. Bills } 163895820184SJason M. Bills } 1639c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16403648c8beSEd Tanous if (skip + top < entryCount) 1641c4bf6374SJason M. Bills { 1642c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 16434978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 16443648c8beSEd Tanous std::to_string(skip + top); 1645c4bf6374SJason M. Bills } 16467e860f15SJohn Edward Broadbent }); 1647897967deSJason M. Bills } 1648897967deSJason M. Bills 16497e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1650897967deSJason M. Bills { 16517e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 165222d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1653ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 16547e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 165545ca1b86SEd Tanous [&app](const crow::Request& req, 16567e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 165722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16583ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 165945ca1b86SEd Tanous { 166045ca1b86SEd Tanous return; 166145ca1b86SEd Tanous } 16627f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 16637f3e84a1SEd Tanous { 16647f3e84a1SEd Tanous // Option currently returns no systems. TBD 16657f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16667f3e84a1SEd Tanous systemName); 16677f3e84a1SEd Tanous return; 16687f3e84a1SEd Tanous } 166922d268cbSEd Tanous 167022d268cbSEd Tanous if (systemName != "system") 167122d268cbSEd Tanous { 167222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 167322d268cbSEd Tanous systemName); 167422d268cbSEd Tanous return; 167522d268cbSEd Tanous } 167622d268cbSEd Tanous 16777e860f15SJohn Edward Broadbent const std::string& targetID = param; 16788d1b46d7Szhanghch05 16797e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 16807e860f15SJohn Edward Broadbent // entry to find the target entry 1681897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1682897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1683897967deSJason M. Bills std::string logEntry; 1684897967deSJason M. Bills 16857e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16867e860f15SJohn Edward Broadbent // backwards 1687002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1688002d39b4SEd Tanous it++) 1689897967deSJason M. Bills { 1690897967deSJason M. Bills std::ifstream logStream(*it); 1691897967deSJason M. Bills if (!logStream.is_open()) 1692897967deSJason M. Bills { 1693897967deSJason M. Bills continue; 1694897967deSJason M. Bills } 1695897967deSJason M. Bills 1696897967deSJason M. Bills // Reset the unique ID on the first entry 1697897967deSJason M. Bills bool firstEntry = true; 1698897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1699897967deSJason M. Bills { 1700897967deSJason M. Bills std::string idStr; 1701897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1702897967deSJason M. Bills { 1703897967deSJason M. Bills continue; 1704897967deSJason M. Bills } 1705897967deSJason M. Bills firstEntry = false; 1706897967deSJason M. Bills 1707897967deSJason M. Bills if (idStr == targetID) 1708897967deSJason M. Bills { 1709de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1710ac992cdeSJason M. Bills LogParseError status = 1711ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1712ac992cdeSJason M. Bills if (status != LogParseError::success) 1713897967deSJason M. Bills { 1714897967deSJason M. Bills messages::internalError(asyncResp->res); 1715897967deSJason M. Bills return; 1716897967deSJason M. Bills } 1717d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1718897967deSJason M. Bills return; 1719897967deSJason M. Bills } 1720897967deSJason M. Bills } 1721897967deSJason M. Bills } 1722897967deSJason M. Bills // Requested ID was not found 17239db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 17247e860f15SJohn Edward Broadbent }); 172508a4e4b5SAnthony Wilson } 172608a4e4b5SAnthony Wilson 17277e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 172808a4e4b5SAnthony Wilson { 172922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1730ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1731002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1732002d39b4SEd Tanous [&app](const crow::Request& req, 173322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 173422d268cbSEd Tanous const std::string& systemName) { 17353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 173645ca1b86SEd Tanous { 173745ca1b86SEd Tanous return; 173845ca1b86SEd Tanous } 17397f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 17407f3e84a1SEd Tanous { 17417f3e84a1SEd Tanous // Option currently returns no systems. TBD 17427f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17437f3e84a1SEd Tanous systemName); 17447f3e84a1SEd Tanous return; 17457f3e84a1SEd Tanous } 174622d268cbSEd Tanous if (systemName != "system") 174722d268cbSEd Tanous { 174822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 174922d268cbSEd Tanous systemName); 175022d268cbSEd Tanous return; 175122d268cbSEd Tanous } 175222d268cbSEd Tanous 17537e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 17547e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 175508a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 175608a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 175708a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 175808a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 175908a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 176008a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 176108a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 176208a4e4b5SAnthony Wilson 1763cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1764cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 17655eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 17665eb468daSGeorge Liu dbus::utility::getManagedObjects( 17675eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 17685e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1769914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1770cb92c03bSAndrew Geissler if (ec) 1771cb92c03bSAndrew Geissler { 1772cb92c03bSAndrew Geissler // TODO Handle for specific error code 177362598e31SEd Tanous BMCWEB_LOG_ERROR( 177462598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1775cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1776cb92c03bSAndrew Geissler return; 1777cb92c03bSAndrew Geissler } 17783544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 17799eb808c1SEd Tanous for (const auto& objectPath : resp) 1780cb92c03bSAndrew Geissler { 1781914e2d5dSEd Tanous const uint32_t* id = nullptr; 1782c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1783c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1784914e2d5dSEd Tanous const std::string* severity = nullptr; 1785914e2d5dSEd Tanous const std::string* message = nullptr; 1786914e2d5dSEd Tanous const std::string* filePath = nullptr; 17879c11a172SVijay Lobo const std::string* resolution = nullptr; 178875710de2SXiaochao Ma bool resolved = false; 17899017faf2SAbhishek Patel const std::string* notify = nullptr; 17909017faf2SAbhishek Patel 17919eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1792f86bb901SAdriana Kobylak { 1793f86bb901SAdriana Kobylak if (interfaceMap.first == 1794f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1795f86bb901SAdriana Kobylak { 1796002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1797cb92c03bSAndrew Geissler { 1798cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1799cb92c03bSAndrew Geissler { 1800002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1801cb92c03bSAndrew Geissler } 1802cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1803cb92c03bSAndrew Geissler { 1804002d39b4SEd Tanous timestamp = 1805002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18067e860f15SJohn Edward Broadbent } 1807002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 18087e860f15SJohn Edward Broadbent { 1809002d39b4SEd Tanous updateTimestamp = 1810002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18117e860f15SJohn Edward Broadbent } 18127e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 18137e860f15SJohn Edward Broadbent { 18147e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 18157e860f15SJohn Edward Broadbent &propertyMap.second); 18167e860f15SJohn Edward Broadbent } 18179c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 18189c11a172SVijay Lobo { 18199c11a172SVijay Lobo resolution = std::get_if<std::string>( 18209c11a172SVijay Lobo &propertyMap.second); 18219c11a172SVijay Lobo } 18227e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 18237e860f15SJohn Edward Broadbent { 18247e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 18257e860f15SJohn Edward Broadbent &propertyMap.second); 18267e860f15SJohn Edward Broadbent } 18277e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 18287e860f15SJohn Edward Broadbent { 1829914e2d5dSEd Tanous const bool* resolveptr = 1830002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 18317e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 18327e860f15SJohn Edward Broadbent { 1833002d39b4SEd Tanous messages::internalError(asyncResp->res); 18347e860f15SJohn Edward Broadbent return; 18357e860f15SJohn Edward Broadbent } 18367e860f15SJohn Edward Broadbent resolved = *resolveptr; 18377e860f15SJohn Edward Broadbent } 18389017faf2SAbhishek Patel else if (propertyMap.first == 18399017faf2SAbhishek Patel "ServiceProviderNotify") 18409017faf2SAbhishek Patel { 18419017faf2SAbhishek Patel notify = std::get_if<std::string>( 18429017faf2SAbhishek Patel &propertyMap.second); 18439017faf2SAbhishek Patel if (notify == nullptr) 18449017faf2SAbhishek Patel { 18459017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18469017faf2SAbhishek Patel return; 18479017faf2SAbhishek Patel } 18489017faf2SAbhishek Patel } 18497e860f15SJohn Edward Broadbent } 18507e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 18517e860f15SJohn Edward Broadbent severity == nullptr) 18527e860f15SJohn Edward Broadbent { 18537e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18547e860f15SJohn Edward Broadbent return; 18557e860f15SJohn Edward Broadbent } 18567e860f15SJohn Edward Broadbent } 18577e860f15SJohn Edward Broadbent else if (interfaceMap.first == 18587e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 18597e860f15SJohn Edward Broadbent { 1860002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 18617e860f15SJohn Edward Broadbent { 18627e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 18637e860f15SJohn Edward Broadbent { 18647e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 18657e860f15SJohn Edward Broadbent &propertyMap.second); 18667e860f15SJohn Edward Broadbent } 18677e860f15SJohn Edward Broadbent } 18687e860f15SJohn Edward Broadbent } 18697e860f15SJohn Edward Broadbent } 18707e860f15SJohn Edward Broadbent // Object path without the 18717e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 18727e860f15SJohn Edward Broadbent // and continue. 18737e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1874c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1875c419c759SEd Tanous updateTimestamp == nullptr) 18767e860f15SJohn Edward Broadbent { 18777e860f15SJohn Edward Broadbent continue; 18787e860f15SJohn Edward Broadbent } 18793544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 18809c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1881ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1882ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1883ef4c65b7SEd Tanous std::to_string(*id)); 18847e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 18857e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 18867e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 18877e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 18889c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 18899c11a172SVijay Lobo { 18909c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 18919c11a172SVijay Lobo } 18929017faf2SAbhishek Patel std::optional<bool> notifyAction = 18939017faf2SAbhishek Patel getProviderNotifyAction(*notify); 18949017faf2SAbhishek Patel if (notifyAction) 18959017faf2SAbhishek Patel { 18969017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 18979017faf2SAbhishek Patel } 18987e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 18997e860f15SJohn Edward Broadbent thisEntry["Severity"] = 19007e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 19017e860f15SJohn Edward Broadbent thisEntry["Created"] = 19022b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 19037e860f15SJohn Edward Broadbent thisEntry["Modified"] = 19042b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 19057e860f15SJohn Edward Broadbent if (filePath != nullptr) 19067e860f15SJohn Edward Broadbent { 19077e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 19080fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 19097e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 19107e860f15SJohn Edward Broadbent } 19117e860f15SJohn Edward Broadbent } 19123544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 19133544d2a7SEd Tanous const nlohmann::json& right) { 19147e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 19157e860f15SJohn Edward Broadbent }); 19167e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 19177e860f15SJohn Edward Broadbent entriesArray.size(); 19183544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 19195eb468daSGeorge Liu }); 19207e860f15SJohn Edward Broadbent }); 19217e860f15SJohn Edward Broadbent } 19227e860f15SJohn Edward Broadbent 19237e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 19247e860f15SJohn Edward Broadbent { 19257e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 192622d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1927ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1928002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1929002d39b4SEd Tanous [&app](const crow::Request& req, 19307e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 193122d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19323ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19337e860f15SJohn Edward Broadbent { 193445ca1b86SEd Tanous return; 193545ca1b86SEd Tanous } 19367f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19377f3e84a1SEd Tanous { 19387f3e84a1SEd Tanous // Option currently returns no systems. TBD 19397f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19407f3e84a1SEd Tanous systemName); 19417f3e84a1SEd Tanous return; 19427f3e84a1SEd Tanous } 194322d268cbSEd Tanous if (systemName != "system") 194422d268cbSEd Tanous { 194522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 194622d268cbSEd Tanous systemName); 194722d268cbSEd Tanous return; 194822d268cbSEd Tanous } 194922d268cbSEd Tanous 19507e860f15SJohn Edward Broadbent std::string entryID = param; 19517e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 19527e860f15SJohn Edward Broadbent 19537e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 19547e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1955d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1956d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1957d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 19585e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1959b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 19607e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 19617e860f15SJohn Edward Broadbent { 1962d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1963d1bde9e5SKrzysztof Grobelny entryID); 19647e860f15SJohn Edward Broadbent return; 19657e860f15SJohn Edward Broadbent } 19667e860f15SJohn Edward Broadbent if (ec) 19677e860f15SJohn Edward Broadbent { 196862598e31SEd Tanous BMCWEB_LOG_ERROR( 196962598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 19707e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 19717e860f15SJohn Edward Broadbent return; 19727e860f15SJohn Edward Broadbent } 1973914e2d5dSEd Tanous const uint32_t* id = nullptr; 1974c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1975c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1976914e2d5dSEd Tanous const std::string* severity = nullptr; 1977914e2d5dSEd Tanous const std::string* message = nullptr; 1978914e2d5dSEd Tanous const std::string* filePath = nullptr; 19799c11a172SVijay Lobo const std::string* resolution = nullptr; 19807e860f15SJohn Edward Broadbent bool resolved = false; 19819017faf2SAbhishek Patel const std::string* notify = nullptr; 19827e860f15SJohn Edward Broadbent 1983d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1984d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1985d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 19869c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 19879017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 19889017faf2SAbhishek Patel "ServiceProviderNotify", notify); 1989d1bde9e5SKrzysztof Grobelny 1990d1bde9e5SKrzysztof Grobelny if (!success) 199175710de2SXiaochao Ma { 199275710de2SXiaochao Ma messages::internalError(asyncResp->res); 199375710de2SXiaochao Ma return; 199475710de2SXiaochao Ma } 1995d1bde9e5SKrzysztof Grobelny 1996002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 19979017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 19989017faf2SAbhishek Patel notify == nullptr) 1999f86bb901SAdriana Kobylak { 2000ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 2001271584abSEd Tanous return; 2002271584abSEd Tanous } 20039017faf2SAbhishek Patel 2004f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 20059c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 2006ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2007ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 2008ef4c65b7SEd Tanous std::to_string(*id)); 200945ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 2010f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 2011f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 2012f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 20139017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 20149017faf2SAbhishek Patel if (notifyAction) 20159017faf2SAbhishek Patel { 20169017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 20179017faf2SAbhishek Patel *notifyAction; 20189017faf2SAbhishek Patel } 20199c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 20209c11a172SVijay Lobo { 20219c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 20229c11a172SVijay Lobo } 2023f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 2024f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 2025f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 2026f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 20272b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 2028f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 20292b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 2030f86bb901SAdriana Kobylak if (filePath != nullptr) 2031f86bb901SAdriana Kobylak { 2032f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 2033e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 2034e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 2035f86bb901SAdriana Kobylak } 2036d1bde9e5SKrzysztof Grobelny }); 20377e860f15SJohn Edward Broadbent }); 2038336e96c6SChicago Duan 20397e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 204022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2041ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 20427e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 204345ca1b86SEd Tanous [&app](const crow::Request& req, 20447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 204522d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 20463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 204745ca1b86SEd Tanous { 204845ca1b86SEd Tanous return; 204945ca1b86SEd Tanous } 20507f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20517f3e84a1SEd Tanous { 20527f3e84a1SEd Tanous // Option currently returns no systems. TBD 20537f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20547f3e84a1SEd Tanous systemName); 20557f3e84a1SEd Tanous return; 20567f3e84a1SEd Tanous } 205722d268cbSEd Tanous if (systemName != "system") 205822d268cbSEd Tanous { 205922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 206022d268cbSEd Tanous systemName); 206122d268cbSEd Tanous return; 206222d268cbSEd Tanous } 206375710de2SXiaochao Ma std::optional<bool> resolved; 206475710de2SXiaochao Ma 206515ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 20667e860f15SJohn Edward Broadbent resolved)) 206775710de2SXiaochao Ma { 206875710de2SXiaochao Ma return; 206975710de2SXiaochao Ma } 207062598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 207175710de2SXiaochao Ma 20723eb66652SAsmitha Karunanithi setDbusProperty(asyncResp, "xyz.openbmc_project.Logging", 20739ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 20743eb66652SAsmitha Karunanithi "xyz.openbmc_project.Logging.Entry", "Resolved", 20753eb66652SAsmitha Karunanithi "Resolved", *resolved); 20767e860f15SJohn Edward Broadbent }); 207775710de2SXiaochao Ma 20787e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 207922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2080ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2081ed398213SEd Tanous 2082002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2083002d39b4SEd Tanous [&app](const crow::Request& req, 2084002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 208522d268cbSEd Tanous const std::string& systemName, const std::string& param) { 20863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2087336e96c6SChicago Duan { 208845ca1b86SEd Tanous return; 208945ca1b86SEd Tanous } 20907f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20917f3e84a1SEd Tanous { 20927f3e84a1SEd Tanous // Option currently returns no systems. TBD 20937f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20947f3e84a1SEd Tanous systemName); 20957f3e84a1SEd Tanous return; 20967f3e84a1SEd Tanous } 209722d268cbSEd Tanous if (systemName != "system") 209822d268cbSEd Tanous { 209922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 210022d268cbSEd Tanous systemName); 210122d268cbSEd Tanous return; 210222d268cbSEd Tanous } 210362598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 2104336e96c6SChicago Duan 21057e860f15SJohn Edward Broadbent std::string entryID = param; 2106336e96c6SChicago Duan 2107336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 2108336e96c6SChicago Duan 2109336e96c6SChicago Duan // Process response from Logging service. 21105a39f77aSPatrick Williams auto respHandler = [asyncResp, 21115a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 211262598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 2113336e96c6SChicago Duan if (ec) 2114336e96c6SChicago Duan { 21153de8d8baSGeorge Liu if (ec.value() == EBADR) 21163de8d8baSGeorge Liu { 211745ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 211845ca1b86SEd Tanous entryID); 21193de8d8baSGeorge Liu return; 21203de8d8baSGeorge Liu } 2121336e96c6SChicago Duan // TODO Handle for specific error code 212262598e31SEd Tanous BMCWEB_LOG_ERROR( 212362598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 212462598e31SEd Tanous ec); 2125336e96c6SChicago Duan asyncResp->res.result( 2126336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 2127336e96c6SChicago Duan return; 2128336e96c6SChicago Duan } 2129336e96c6SChicago Duan 2130336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 2131336e96c6SChicago Duan }; 2132336e96c6SChicago Duan 2133336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2134336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2135336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2136336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2137336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 21387e860f15SJohn Edward Broadbent }); 2139400fd1fbSAdriana Kobylak } 2140400fd1fbSAdriana Kobylak 2141b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2142b7028ebfSSpencer Ku 2143b7028ebfSSpencer Ku inline bool 2144b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2145b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2146b7028ebfSSpencer Ku { 2147b7028ebfSSpencer Ku std::error_code ec; 2148b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2149b7028ebfSSpencer Ku if (ec) 2150b7028ebfSSpencer Ku { 2151bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2152b7028ebfSSpencer Ku return false; 2153b7028ebfSSpencer Ku } 2154b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2155b7028ebfSSpencer Ku { 2156b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2157b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2158b7028ebfSSpencer Ku // path 215911ba3979SEd Tanous if (filename.starts_with("log")) 2160b7028ebfSSpencer Ku { 2161b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2162b7028ebfSSpencer Ku } 2163b7028ebfSSpencer Ku } 2164b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2165b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2166b7028ebfSSpencer Ku // descending order. 2167b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2168b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2169b7028ebfSSpencer Ku 2170b7028ebfSSpencer Ku return true; 2171b7028ebfSSpencer Ku } 2172b7028ebfSSpencer Ku 217302cad96eSEd Tanous inline bool getHostLoggerEntries( 217402cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 217502cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2176b7028ebfSSpencer Ku { 2177b7028ebfSSpencer Ku GzFileReader logFile; 2178b7028ebfSSpencer Ku 2179b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2180b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2181b7028ebfSSpencer Ku { 2182b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2183b7028ebfSSpencer Ku { 218462598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2185b7028ebfSSpencer Ku return false; 2186b7028ebfSSpencer Ku } 2187b7028ebfSSpencer Ku } 2188b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2189b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2190b7028ebfSSpencer Ku if (!lastMessage.empty()) 2191b7028ebfSSpencer Ku { 2192b7028ebfSSpencer Ku logCount++; 2193b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2194b7028ebfSSpencer Ku { 2195b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2196b7028ebfSSpencer Ku } 2197b7028ebfSSpencer Ku } 2198b7028ebfSSpencer Ku return true; 2199b7028ebfSSpencer Ku } 2200b7028ebfSSpencer Ku 2201b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2202b7028ebfSSpencer Ku const std::string& msg, 22036d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2204b7028ebfSSpencer Ku { 2205b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 22069c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2207ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2208ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2209ef4c65b7SEd Tanous logEntryID); 22106d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 22116d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 22126d6574c9SJason M. Bills logEntryJson["Message"] = msg; 22136d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 22146d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 22156d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2216b7028ebfSSpencer Ku } 2217b7028ebfSSpencer Ku 2218b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2219b7028ebfSSpencer Ku { 222022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2221b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 22221476687dSEd Tanous .methods(boost::beast::http::verb::get)( 22231476687dSEd Tanous [&app](const crow::Request& req, 222422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 222522d268cbSEd Tanous const std::string& systemName) { 22263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 222745ca1b86SEd Tanous { 222845ca1b86SEd Tanous return; 222945ca1b86SEd Tanous } 22307f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22317f3e84a1SEd Tanous { 22327f3e84a1SEd Tanous // Option currently returns no systems. TBD 22337f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22347f3e84a1SEd Tanous systemName); 22357f3e84a1SEd Tanous return; 22367f3e84a1SEd Tanous } 223722d268cbSEd Tanous if (systemName != "system") 223822d268cbSEd Tanous { 223922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 224022d268cbSEd Tanous systemName); 224122d268cbSEd Tanous return; 224222d268cbSEd Tanous } 2243b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2244b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2245b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2246b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2247b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2248b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2249b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 22501476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 22511476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2252b7028ebfSSpencer Ku }); 2253b7028ebfSSpencer Ku } 2254b7028ebfSSpencer Ku 2255b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2256b7028ebfSSpencer Ku { 2257b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 225822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2259b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2260002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2261002d39b4SEd Tanous [&app](const crow::Request& req, 226222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 226322d268cbSEd Tanous const std::string& systemName) { 2264c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2265c937d2bfSEd Tanous .canDelegateTop = true, 2266c937d2bfSEd Tanous .canDelegateSkip = true, 2267c937d2bfSEd Tanous }; 2268c937d2bfSEd Tanous query_param::Query delegatedQuery; 2269c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22703ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2271b7028ebfSSpencer Ku { 2272b7028ebfSSpencer Ku return; 2273b7028ebfSSpencer Ku } 22747f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22757f3e84a1SEd Tanous { 22767f3e84a1SEd Tanous // Option currently returns no systems. TBD 22777f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22787f3e84a1SEd Tanous systemName); 22797f3e84a1SEd Tanous return; 22807f3e84a1SEd Tanous } 228122d268cbSEd Tanous if (systemName != "system") 228222d268cbSEd Tanous { 228322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 228422d268cbSEd Tanous systemName); 228522d268cbSEd Tanous return; 228622d268cbSEd Tanous } 2287b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2288b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2289b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2290b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2291b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2292b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2293b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 22940fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2295b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2296b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2297b7028ebfSSpencer Ku 2298b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2299b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2300b7028ebfSSpencer Ku { 2301bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2302b7028ebfSSpencer Ku return; 2303b7028ebfSSpencer Ku } 23043648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 23053648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 23065143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2307b7028ebfSSpencer Ku size_t logCount = 0; 2308b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2309b7028ebfSSpencer Ku // control by skip and top. 2310b7028ebfSSpencer Ku std::vector<std::string> logEntries; 23113648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 23123648c8beSEd Tanous logCount)) 2313b7028ebfSSpencer Ku { 2314b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2315b7028ebfSSpencer Ku return; 2316b7028ebfSSpencer Ku } 2317b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2318b7028ebfSSpencer Ku // log count 231926f6976fSEd Tanous if (logEntries.empty()) 2320b7028ebfSSpencer Ku { 2321b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2322b7028ebfSSpencer Ku return; 2323b7028ebfSSpencer Ku } 232426f6976fSEd Tanous if (!logEntries.empty()) 2325b7028ebfSSpencer Ku { 2326b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2327b7028ebfSSpencer Ku { 23286d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23293648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 23303648c8beSEd Tanous hostLogEntry); 2331b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2332b7028ebfSSpencer Ku } 2333b7028ebfSSpencer Ku 2334b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 23353648c8beSEd Tanous if (skip + top < logCount) 2336b7028ebfSSpencer Ku { 2337b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 23380fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 23393648c8beSEd Tanous std::to_string(skip + top); 2340b7028ebfSSpencer Ku } 2341b7028ebfSSpencer Ku } 2342b7028ebfSSpencer Ku }); 2343b7028ebfSSpencer Ku } 2344b7028ebfSSpencer Ku 2345b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2346b7028ebfSSpencer Ku { 2347b7028ebfSSpencer Ku BMCWEB_ROUTE( 234822d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2349b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2350b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 235145ca1b86SEd Tanous [&app](const crow::Request& req, 2352b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 235322d268cbSEd Tanous const std::string& systemName, const std::string& param) { 23543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 235545ca1b86SEd Tanous { 235645ca1b86SEd Tanous return; 235745ca1b86SEd Tanous } 23587f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 23597f3e84a1SEd Tanous { 23607f3e84a1SEd Tanous // Option currently returns no systems. TBD 23617f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 23627f3e84a1SEd Tanous systemName); 23637f3e84a1SEd Tanous return; 23647f3e84a1SEd Tanous } 236522d268cbSEd Tanous if (systemName != "system") 236622d268cbSEd Tanous { 236722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 236822d268cbSEd Tanous systemName); 236922d268cbSEd Tanous return; 237022d268cbSEd Tanous } 2371b7028ebfSSpencer Ku const std::string& targetID = param; 2372b7028ebfSSpencer Ku 2373b7028ebfSSpencer Ku uint64_t idInt = 0; 2374ca45aa3cSEd Tanous 237584396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 237684396af9SPatrick Williams idInt); 23779db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 23789db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2379b7028ebfSSpencer Ku { 23809db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2381b7028ebfSSpencer Ku return; 2382b7028ebfSSpencer Ku } 2383b7028ebfSSpencer Ku 2384b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2385b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2386b7028ebfSSpencer Ku { 2387bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2388b7028ebfSSpencer Ku return; 2389b7028ebfSSpencer Ku } 2390b7028ebfSSpencer Ku 2391b7028ebfSSpencer Ku size_t logCount = 0; 23923648c8beSEd Tanous size_t top = 1; 2393b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2394b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2395b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2396b7028ebfSSpencer Ku // get that entry 2397002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2398002d39b4SEd Tanous logCount)) 2399b7028ebfSSpencer Ku { 2400b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2401b7028ebfSSpencer Ku return; 2402b7028ebfSSpencer Ku } 2403b7028ebfSSpencer Ku 2404b7028ebfSSpencer Ku if (!logEntries.empty()) 2405b7028ebfSSpencer Ku { 24066d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 24076d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 24086d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2409b7028ebfSSpencer Ku return; 2410b7028ebfSSpencer Ku } 2411b7028ebfSSpencer Ku 2412b7028ebfSSpencer Ku // Requested ID was not found 24139db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2414b7028ebfSSpencer Ku }); 2415b7028ebfSSpencer Ku } 2416b7028ebfSSpencer Ku 2417dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2418fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2419fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 24201da66f75SEd Tanous { 24213ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 242245ca1b86SEd Tanous { 242345ca1b86SEd Tanous return; 242445ca1b86SEd Tanous } 24257e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24267e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2427e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 24281da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2429e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2430e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2431002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2432e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 24331da66f75SEd Tanous "Collection of LogServices for this Manager"; 2434002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2435c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2436fdd26906SClaire Weinan 2437c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2438613dabeaSEd Tanous nlohmann::json::object_t journal; 2439613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2440b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2441c4bf6374SJason M. Bills #endif 2442fdd26906SClaire Weinan 2443fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2444fdd26906SClaire Weinan 2445fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 244615912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24477a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 24487a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 24497a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2450fdd26906SClaire Weinan [asyncResp]( 24517a1dbc48SGeorge Liu const boost::system::error_code& ec, 2452fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2453fdd26906SClaire Weinan if (ec) 2454fdd26906SClaire Weinan { 245562598e31SEd Tanous BMCWEB_LOG_ERROR( 245662598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 245762598e31SEd Tanous ec); 2458fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2459fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2460fdd26906SClaire Weinan return; 2461fdd26906SClaire Weinan } 2462fdd26906SClaire Weinan 2463fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2464fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2465fdd26906SClaire Weinan 2466fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2467fdd26906SClaire Weinan { 2468fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2469fdd26906SClaire Weinan { 2470613dabeaSEd Tanous nlohmann::json::object_t member; 2471613dabeaSEd Tanous member["@odata.id"] = 2472613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2473b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2474fdd26906SClaire Weinan } 2475fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2476fdd26906SClaire Weinan { 2477613dabeaSEd Tanous nlohmann::json::object_t member; 2478613dabeaSEd Tanous member["@odata.id"] = 2479613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2480b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2481fdd26906SClaire Weinan } 2482fdd26906SClaire Weinan } 2483fdd26906SClaire Weinan 2484e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2485fdd26906SClaire Weinan logServiceArrayLocal.size(); 24867a1dbc48SGeorge Liu }); 2487fdd26906SClaire Weinan #endif 2488fdd26906SClaire Weinan } 2489fdd26906SClaire Weinan 2490fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2491fdd26906SClaire Weinan { 2492fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2493fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2494fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2495dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2496e1f26343SJason M. Bills } 2497e1f26343SJason M. Bills 24987e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2499e1f26343SJason M. Bills { 25007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2501ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 25027e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 250345ca1b86SEd Tanous [&app](const crow::Request& req, 250445ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 25053ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25067e860f15SJohn Edward Broadbent { 250745ca1b86SEd Tanous return; 250845ca1b86SEd Tanous } 2509e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2510b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 25110f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 25120f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2513002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2514002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2515ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2516e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 25177c8c4058STejas Patil 25187c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 25192b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2520002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 25217c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 25227c8c4058STejas Patil redfishDateTimeOffset.second; 25237c8c4058STejas Patil 25241476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 25251476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 25267e860f15SJohn Edward Broadbent }); 2527e1f26343SJason M. Bills } 2528e1f26343SJason M. Bills 25293a48b3a2SJason M. Bills static int 25303a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2531e1f26343SJason M. Bills sd_journal* journal, 25323a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2533e1f26343SJason M. Bills { 2534e1f26343SJason M. Bills // Get the Log Entry contents 2535e1f26343SJason M. Bills int ret = 0; 2536e1f26343SJason M. Bills 2537a8fe54f0SJason M. Bills std::string message; 2538a8fe54f0SJason M. Bills std::string_view syslogID; 2539a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2540a8fe54f0SJason M. Bills if (ret < 0) 2541a8fe54f0SJason M. Bills { 2542bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 254362598e31SEd Tanous strerror(-ret)); 2544a8fe54f0SJason M. Bills } 2545a8fe54f0SJason M. Bills if (!syslogID.empty()) 2546a8fe54f0SJason M. Bills { 2547a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2548a8fe54f0SJason M. Bills } 2549a8fe54f0SJason M. Bills 255039e77504SEd Tanous std::string_view msg; 255116428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2552e1f26343SJason M. Bills if (ret < 0) 2553e1f26343SJason M. Bills { 255462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2555e1f26343SJason M. Bills return 1; 2556e1f26343SJason M. Bills } 2557a8fe54f0SJason M. Bills message += std::string(msg); 2558e1f26343SJason M. Bills 2559e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2560271584abSEd Tanous long int severity = 8; // Default to an invalid priority 256116428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2562e1f26343SJason M. Bills if (ret < 0) 2563e1f26343SJason M. Bills { 2564bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2565e1f26343SJason M. Bills } 2566e1f26343SJason M. Bills 2567e1f26343SJason M. Bills // Get the Created time from the timestamp 256816428a1aSJason M. Bills std::string entryTimeStr; 256916428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2570e1f26343SJason M. Bills { 257116428a1aSJason M. Bills return 1; 2572e1f26343SJason M. Bills } 2573e1f26343SJason M. Bills 2574e1f26343SJason M. Bills // Fill in the log entry with the gathered data 25759c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2576ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2577ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2578eddfc437SWilly Tu bmcJournalLogEntryID); 257984afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 258084afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 258184afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 258284afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 2583ddf3564eSEd Tanous log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK; 2584ddf3564eSEd Tanous if (severity <= 2) 2585ddf3564eSEd Tanous { 2586ddf3564eSEd Tanous severityEnum = log_entry::EventSeverity::Critical; 2587ddf3564eSEd Tanous } 2588ddf3564eSEd Tanous else if (severity <= 4) 2589ddf3564eSEd Tanous { 2590ddf3564eSEd Tanous severityEnum = log_entry::EventSeverity::Warning; 2591ddf3564eSEd Tanous } 2592ddf3564eSEd Tanous 2593ddf3564eSEd Tanous bmcJournalLogEntryJson["Severity"] = severityEnum; 259484afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 259584afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2596e1f26343SJason M. Bills return 0; 2597e1f26343SJason M. Bills } 2598e1f26343SJason M. Bills 25997e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2600e1f26343SJason M. Bills { 26017e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2602ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2603002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2604002d39b4SEd Tanous [&app](const crow::Request& req, 2605002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2606c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2607c937d2bfSEd Tanous .canDelegateTop = true, 2608c937d2bfSEd Tanous .canDelegateSkip = true, 2609c937d2bfSEd Tanous }; 2610c937d2bfSEd Tanous query_param::Query delegatedQuery; 2611c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 26123ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2613193ad2faSJason M. Bills { 2614193ad2faSJason M. Bills return; 2615193ad2faSJason M. Bills } 26163648c8beSEd Tanous 26173648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 26185143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 26193648c8beSEd Tanous 26207e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 26217e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2622e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2623e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 26240f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 26250f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2626e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2627e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2628e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 26290fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2630e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2631e1f26343SJason M. Bills 26327e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 26337e860f15SJohn Edward Broadbent // unique ID for each entry 2634e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2635e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2636e1f26343SJason M. Bills if (ret < 0) 2637e1f26343SJason M. Bills { 263862598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2639f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2640e1f26343SJason M. Bills return; 2641e1f26343SJason M. Bills } 26420fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 26430fda0f12SGeorge Liu journalTmp, sd_journal_close); 2644e1f26343SJason M. Bills journalTmp = nullptr; 2645b01bf299SEd Tanous uint64_t entryCount = 0; 2646e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2647e85d6b16SJason M. Bills bool firstEntry = true; 2648e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2649e1f26343SJason M. Bills { 2650193ad2faSJason M. Bills entryCount++; 26517e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 26527e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 26533648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2654193ad2faSJason M. Bills { 2655193ad2faSJason M. Bills continue; 2656193ad2faSJason M. Bills } 2657193ad2faSJason M. Bills 265816428a1aSJason M. Bills std::string idStr; 2659e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2660e1f26343SJason M. Bills { 2661e1f26343SJason M. Bills continue; 2662e1f26343SJason M. Bills } 2663e85d6b16SJason M. Bills firstEntry = false; 2664e85d6b16SJason M. Bills 26653a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2666c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2667c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2668e1f26343SJason M. Bills { 2669f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2670e1f26343SJason M. Bills return; 2671e1f26343SJason M. Bills } 2672b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2673e1f26343SJason M. Bills } 2674193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 26753648c8beSEd Tanous if (skip + top < entryCount) 2676193ad2faSJason M. Bills { 2677193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 26780fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 26793648c8beSEd Tanous std::to_string(skip + top); 2680193ad2faSJason M. Bills } 26817e860f15SJohn Edward Broadbent }); 2682e1f26343SJason M. Bills } 2683e1f26343SJason M. Bills 26847e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2685e1f26343SJason M. Bills { 26867e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 26877e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2688ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 26897e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 269045ca1b86SEd Tanous [&app](const crow::Request& req, 26917e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 26927e860f15SJohn Edward Broadbent const std::string& entryID) { 26933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 269445ca1b86SEd Tanous { 269545ca1b86SEd Tanous return; 269645ca1b86SEd Tanous } 2697e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 269875e8e218SMyung Bae sd_id128_t bootID{}; 2699e1f26343SJason M. Bills uint64_t ts = 0; 2700271584abSEd Tanous uint64_t index = 0; 270175e8e218SMyung Bae if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index)) 2702e1f26343SJason M. Bills { 270316428a1aSJason M. Bills return; 2704e1f26343SJason M. Bills } 2705e1f26343SJason M. Bills 2706e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2707e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2708e1f26343SJason M. Bills if (ret < 0) 2709e1f26343SJason M. Bills { 271062598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2711f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2712e1f26343SJason M. Bills return; 2713e1f26343SJason M. Bills } 2714002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2715002d39b4SEd Tanous journalTmp, sd_journal_close); 2716e1f26343SJason M. Bills journalTmp = nullptr; 27177e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 27187e860f15SJohn Edward Broadbent // index tracking the unique ID 2719af07e3f5SJason M. Bills std::string idStr; 2720af07e3f5SJason M. Bills bool firstEntry = true; 272175e8e218SMyung Bae ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts); 27222056b6d1SManojkiran Eda if (ret < 0) 27232056b6d1SManojkiran Eda { 272462598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 272562598e31SEd Tanous strerror(-ret)); 27262056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 27272056b6d1SManojkiran Eda return; 27282056b6d1SManojkiran Eda } 2729271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2730e1f26343SJason M. Bills { 2731e1f26343SJason M. Bills sd_journal_next(journal.get()); 2732af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2733af07e3f5SJason M. Bills { 2734af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2735af07e3f5SJason M. Bills return; 2736af07e3f5SJason M. Bills } 2737af07e3f5SJason M. Bills firstEntry = false; 2738af07e3f5SJason M. Bills } 2739c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2740af07e3f5SJason M. Bills if (idStr != entryID) 2741c4bf6374SJason M. Bills { 27429db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2743c4bf6374SJason M. Bills return; 2744c4bf6374SJason M. Bills } 2745c4bf6374SJason M. Bills 27463a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2747c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 27483a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2749e1f26343SJason M. Bills { 2750f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2751e1f26343SJason M. Bills return; 2752e1f26343SJason M. Bills } 2753d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 27547e860f15SJohn Edward Broadbent }); 2755c9bb6861Sraviteja-b } 2756c9bb6861Sraviteja-b 2757fdd26906SClaire Weinan inline void 2758fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2759fdd26906SClaire Weinan const std::string& dumpType) 2760c9bb6861Sraviteja-b { 2761fdd26906SClaire Weinan std::string dumpPath; 2762fdd26906SClaire Weinan std::string overWritePolicy; 2763fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2764fdd26906SClaire Weinan 2765fdd26906SClaire Weinan if (dumpType == "BMC") 276645ca1b86SEd Tanous { 2767fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2768fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2769fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2770fdd26906SClaire Weinan } 2771fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2772fdd26906SClaire Weinan { 2773fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2774fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2775fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2776fdd26906SClaire Weinan } 2777fdd26906SClaire Weinan else if (dumpType == "System") 2778fdd26906SClaire Weinan { 2779fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2780fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2781fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2782fdd26906SClaire Weinan } 2783fdd26906SClaire Weinan else 2784fdd26906SClaire Weinan { 278562598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 278662598e31SEd Tanous dumpType); 2787fdd26906SClaire Weinan messages::internalError(asyncResp->res); 278845ca1b86SEd Tanous return; 278945ca1b86SEd Tanous } 2790fdd26906SClaire Weinan 2791fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2792fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2793c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2794fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2795fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2796fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 27977c8c4058STejas Patil 27987c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 27992b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 28000fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 28017c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 28027c8c4058STejas Patil redfishDateTimeOffset.second; 28037c8c4058STejas Patil 2804fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2805fdd26906SClaire Weinan 2806fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2807fdd26906SClaire Weinan { 2808002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 28091476687dSEd Tanous ["target"] = 2810fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2811fdd26906SClaire Weinan } 28120d946211SClaire Weinan 28130d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 28140d946211SClaire Weinan dbus::utility::getSubTreePaths( 28150d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 28160d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 28170d946211SClaire Weinan const boost::system::error_code& ec, 28180d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 28190d946211SClaire Weinan if (ec) 28200d946211SClaire Weinan { 282162598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 28220d946211SClaire Weinan // Assume that getting an error simply means there are no dump 28230d946211SClaire Weinan // LogServices. Return without adding any error response. 28240d946211SClaire Weinan return; 28250d946211SClaire Weinan } 282618f8f608SEd Tanous std::string dbusDumpPath = getDumpPath(dumpType); 28270d946211SClaire Weinan for (const std::string& path : subTreePaths) 28280d946211SClaire Weinan { 28290d946211SClaire Weinan if (path == dbusDumpPath) 28300d946211SClaire Weinan { 28310d946211SClaire Weinan asyncResp->res 28320d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 28330d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 28340d946211SClaire Weinan break; 28350d946211SClaire Weinan } 28360d946211SClaire Weinan } 28370d946211SClaire Weinan }); 2838c9bb6861Sraviteja-b } 2839c9bb6861Sraviteja-b 2840fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2841fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2842fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 28437e860f15SJohn Edward Broadbent { 28443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 284545ca1b86SEd Tanous { 284645ca1b86SEd Tanous return; 284745ca1b86SEd Tanous } 2848fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2849fdd26906SClaire Weinan } 2850c9bb6861Sraviteja-b 285122d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 285222d268cbSEd Tanous crow::App& app, const crow::Request& req, 285322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 285422d268cbSEd Tanous const std::string& chassisId) 285522d268cbSEd Tanous { 285622d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 285722d268cbSEd Tanous { 285822d268cbSEd Tanous return; 285922d268cbSEd Tanous } 286022d268cbSEd Tanous if (chassisId != "system") 286122d268cbSEd Tanous { 286222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 286322d268cbSEd Tanous return; 286422d268cbSEd Tanous } 286522d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 286622d268cbSEd Tanous } 286722d268cbSEd Tanous 2868fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2869fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2870fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2871fdd26906SClaire Weinan { 2872fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2873fdd26906SClaire Weinan { 2874fdd26906SClaire Weinan return; 2875fdd26906SClaire Weinan } 2876fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2877fdd26906SClaire Weinan } 2878fdd26906SClaire Weinan 287922d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 288022d268cbSEd Tanous crow::App& app, const crow::Request& req, 288122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 288222d268cbSEd Tanous const std::string& chassisId) 288322d268cbSEd Tanous { 288422d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 288522d268cbSEd Tanous { 288622d268cbSEd Tanous return; 288722d268cbSEd Tanous } 288822d268cbSEd Tanous if (chassisId != "system") 288922d268cbSEd Tanous { 289022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 289122d268cbSEd Tanous return; 289222d268cbSEd Tanous } 289322d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 289422d268cbSEd Tanous } 289522d268cbSEd Tanous 2896fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2897fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2898fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2899fdd26906SClaire Weinan const std::string& dumpId) 2900fdd26906SClaire Weinan { 2901fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2902fdd26906SClaire Weinan { 2903fdd26906SClaire Weinan return; 2904fdd26906SClaire Weinan } 2905fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2906fdd26906SClaire Weinan } 2907168d1b1aSCarson Labrado 290822d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 290922d268cbSEd Tanous crow::App& app, const crow::Request& req, 291022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 291122d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 291222d268cbSEd Tanous { 291322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 291422d268cbSEd Tanous { 291522d268cbSEd Tanous return; 291622d268cbSEd Tanous } 291722d268cbSEd Tanous if (chassisId != "system") 291822d268cbSEd Tanous { 291922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 292022d268cbSEd Tanous return; 292122d268cbSEd Tanous } 292222d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 292322d268cbSEd Tanous } 2924fdd26906SClaire Weinan 2925fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2926fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2927fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2928fdd26906SClaire Weinan const std::string& dumpId) 2929fdd26906SClaire Weinan { 2930fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2931fdd26906SClaire Weinan { 2932fdd26906SClaire Weinan return; 2933fdd26906SClaire Weinan } 2934fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2935fdd26906SClaire Weinan } 2936fdd26906SClaire Weinan 293722d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 293822d268cbSEd Tanous crow::App& app, const crow::Request& req, 293922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 294022d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 294122d268cbSEd Tanous { 294222d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 294322d268cbSEd Tanous { 294422d268cbSEd Tanous return; 294522d268cbSEd Tanous } 294622d268cbSEd Tanous if (chassisId != "system") 294722d268cbSEd Tanous { 294822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 294922d268cbSEd Tanous return; 295022d268cbSEd Tanous } 295122d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 295222d268cbSEd Tanous } 295322d268cbSEd Tanous 2954168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2955168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2956168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2957168d1b1aSCarson Labrado const std::string& dumpId) 2958168d1b1aSCarson Labrado { 2959168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2960168d1b1aSCarson Labrado { 2961168d1b1aSCarson Labrado return; 2962168d1b1aSCarson Labrado } 2963168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2964168d1b1aSCarson Labrado } 2965168d1b1aSCarson Labrado 2966168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2967168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2968168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2969168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2970168d1b1aSCarson Labrado { 2971168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2972168d1b1aSCarson Labrado { 2973168d1b1aSCarson Labrado return; 2974168d1b1aSCarson Labrado } 2975168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2976168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2977168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2978168d1b1aSCarson Labrado { 2979168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2980168d1b1aSCarson Labrado return; 2981168d1b1aSCarson Labrado } 2982168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 2983168d1b1aSCarson Labrado } 2984168d1b1aSCarson Labrado 2985fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 2986fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2987fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2988fdd26906SClaire Weinan { 2989fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2990fdd26906SClaire Weinan { 2991fdd26906SClaire Weinan return; 2992fdd26906SClaire Weinan } 2993fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 2994fdd26906SClaire Weinan } 2995fdd26906SClaire Weinan 299622d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 299722d268cbSEd Tanous crow::App& app, const crow::Request& req, 299822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29997f3e84a1SEd Tanous const std::string& systemName) 300022d268cbSEd Tanous { 300122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 300222d268cbSEd Tanous { 300322d268cbSEd Tanous return; 300422d268cbSEd Tanous } 30057f3e84a1SEd Tanous 30067f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 300722d268cbSEd Tanous { 30087f3e84a1SEd Tanous // Option currently returns no systems. TBD 30097f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30107f3e84a1SEd Tanous systemName); 30117f3e84a1SEd Tanous return; 30127f3e84a1SEd Tanous } 30137f3e84a1SEd Tanous if (systemName != "system") 30147f3e84a1SEd Tanous { 30157f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30167f3e84a1SEd Tanous systemName); 301722d268cbSEd Tanous return; 301822d268cbSEd Tanous } 301922d268cbSEd Tanous createDump(asyncResp, req, "System"); 302022d268cbSEd Tanous } 302122d268cbSEd Tanous 3022fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 3023fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3024fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3025fdd26906SClaire Weinan { 3026fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3027fdd26906SClaire Weinan { 3028fdd26906SClaire Weinan return; 3029fdd26906SClaire Weinan } 3030fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 3031fdd26906SClaire Weinan } 3032fdd26906SClaire Weinan 303322d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 303422d268cbSEd Tanous crow::App& app, const crow::Request& req, 303522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30367f3e84a1SEd Tanous const std::string& systemName) 303722d268cbSEd Tanous { 303822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 303922d268cbSEd Tanous { 304022d268cbSEd Tanous return; 304122d268cbSEd Tanous } 30427f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 304322d268cbSEd Tanous { 30447f3e84a1SEd Tanous // Option currently returns no systems. TBD 30457f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30467f3e84a1SEd Tanous systemName); 30477f3e84a1SEd Tanous return; 30487f3e84a1SEd Tanous } 30497f3e84a1SEd Tanous if (systemName != "system") 30507f3e84a1SEd Tanous { 30517f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30527f3e84a1SEd Tanous systemName); 305322d268cbSEd Tanous return; 305422d268cbSEd Tanous } 305522d268cbSEd Tanous clearDump(asyncResp, "System"); 305622d268cbSEd Tanous } 305722d268cbSEd Tanous 3058fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 3059fdd26906SClaire Weinan { 3060fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 3061fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3062fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3063fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 3064fdd26906SClaire Weinan } 3065fdd26906SClaire Weinan 3066fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 3067fdd26906SClaire Weinan { 3068fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 3069fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3070fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3071fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 3072c9bb6861Sraviteja-b } 3073c9bb6861Sraviteja-b 30747e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 3075c9bb6861Sraviteja-b { 30767e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30777e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3078ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 3079fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3080fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 3081fdd26906SClaire Weinan 30827e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30837e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3084ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 3085fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3086fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 3087c9bb6861Sraviteja-b } 3088c9bb6861Sraviteja-b 3089168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 3090168d1b1aSCarson Labrado { 3091168d1b1aSCarson Labrado BMCWEB_ROUTE( 3092168d1b1aSCarson Labrado app, 30939e9d99daSRavi Teja "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/") 3094168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3095168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3096168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 3097168d1b1aSCarson Labrado } 3098168d1b1aSCarson Labrado 30997e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 3100c9bb6861Sraviteja-b { 31010fda0f12SGeorge Liu BMCWEB_ROUTE( 31020fda0f12SGeorge Liu app, 31030fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3104ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 31057e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 3106fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 3107fdd26906SClaire Weinan std::ref(app), "BMC")); 3108a43be80fSAsmitha Karunanithi } 3109a43be80fSAsmitha Karunanithi 31107e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 311180319af1SAsmitha Karunanithi { 31120fda0f12SGeorge Liu BMCWEB_ROUTE( 31130fda0f12SGeorge Liu app, 31140fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 3115ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 3116fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3117fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 311845ca1b86SEd Tanous } 3119fdd26906SClaire Weinan 3120168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 3121168d1b1aSCarson Labrado { 3122168d1b1aSCarson Labrado BMCWEB_ROUTE( 3123168d1b1aSCarson Labrado app, 31249e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 3125168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3126168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3127168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 3128168d1b1aSCarson Labrado } 3129168d1b1aSCarson Labrado 3130fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3131fdd26906SClaire Weinan { 3132fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 3133fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3134fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3135fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3136fdd26906SClaire Weinan } 3137fdd26906SClaire Weinan 3138fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3139fdd26906SClaire Weinan { 3140fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 3141fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3142fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3143fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3144fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3145fdd26906SClaire Weinan } 3146fdd26906SClaire Weinan 3147fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3148fdd26906SClaire Weinan { 3149fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3150fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3151fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3152fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3153fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3154fdd26906SClaire Weinan 3155fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3156fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3157fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3158fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3159fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3160fdd26906SClaire Weinan } 3161fdd26906SClaire Weinan 3162fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3163fdd26906SClaire Weinan { 3164fdd26906SClaire Weinan BMCWEB_ROUTE( 3165fdd26906SClaire Weinan app, 3166fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 3167fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3168fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3169fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 31705cb1dd27SAsmitha Karunanithi } 31715cb1dd27SAsmitha Karunanithi 31727e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 31735cb1dd27SAsmitha Karunanithi { 317422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3175ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 31766ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 317722d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 31785cb1dd27SAsmitha Karunanithi } 31795cb1dd27SAsmitha Karunanithi 31807e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 31817e860f15SJohn Edward Broadbent { 318222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3183ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 318422d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 318522d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 318622d268cbSEd Tanous std::ref(app))); 31875cb1dd27SAsmitha Karunanithi } 31885cb1dd27SAsmitha Karunanithi 31897e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 31905cb1dd27SAsmitha Karunanithi { 31917e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 319222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3193ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 31946ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 319522d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 31968d1b46d7Szhanghch05 31977e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 319822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3199ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 32006ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 320122d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 32025cb1dd27SAsmitha Karunanithi } 3203c9bb6861Sraviteja-b 32047e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3205c9bb6861Sraviteja-b { 32060fda0f12SGeorge Liu BMCWEB_ROUTE( 32070fda0f12SGeorge Liu app, 320822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3209ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 321022d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 321122d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 321222d268cbSEd Tanous std::ref(app))); 3213a43be80fSAsmitha Karunanithi } 3214a43be80fSAsmitha Karunanithi 32157e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3216a43be80fSAsmitha Karunanithi { 32170fda0f12SGeorge Liu BMCWEB_ROUTE( 32180fda0f12SGeorge Liu app, 321922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3220ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 32216ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 322222d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3223013487e5Sraviteja-b } 3224013487e5Sraviteja-b 32257e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 32261da66f75SEd Tanous { 32273946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32283946028dSAppaRao Puli // method for security reasons. 32291da66f75SEd Tanous /** 32301da66f75SEd Tanous * Functions triggers appropriate requests on DBus 32311da66f75SEd Tanous */ 323222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3233ed398213SEd Tanous // This is incorrect, should be: 3234ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3235432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3236002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3237002d39b4SEd Tanous [&app](const crow::Request& req, 323822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 323922d268cbSEd Tanous const std::string& systemName) { 32403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 324145ca1b86SEd Tanous { 324245ca1b86SEd Tanous return; 324345ca1b86SEd Tanous } 32447f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32457f3e84a1SEd Tanous { 32467f3e84a1SEd Tanous // Option currently returns no systems. TBD 32477f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32487f3e84a1SEd Tanous systemName); 32497f3e84a1SEd Tanous return; 32507f3e84a1SEd Tanous } 325122d268cbSEd Tanous if (systemName != "system") 325222d268cbSEd Tanous { 325322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 325422d268cbSEd Tanous systemName); 325522d268cbSEd Tanous return; 325622d268cbSEd Tanous } 325722d268cbSEd Tanous 32587e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 32597e860f15SJohn Edward Broadbent // SubRoute 32600f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3261424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3262e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32638e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 32644f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 32654f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 326615b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3267e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3268e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 32697c8c4058STejas Patil 32707c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 32712b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 32727c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 32737c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 32747c8c4058STejas Patil redfishDateTimeOffset.second; 32757c8c4058STejas Patil 32761476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3277ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3278002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 32791476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3280002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 32811476687dSEd Tanous ["target"] = 32821476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 32837e860f15SJohn Edward Broadbent }); 32841da66f75SEd Tanous } 32851da66f75SEd Tanous 32867e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 32875b61b5e8SJason M. Bills { 32880fda0f12SGeorge Liu BMCWEB_ROUTE( 32890fda0f12SGeorge Liu app, 329022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3291ed398213SEd Tanous // This is incorrect, should be: 3292ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3293432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 32947e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 329545ca1b86SEd Tanous [&app](const crow::Request& req, 329622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 329722d268cbSEd Tanous const std::string& systemName) { 32983ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 329945ca1b86SEd Tanous { 330045ca1b86SEd Tanous return; 330145ca1b86SEd Tanous } 33027f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 33037f3e84a1SEd Tanous { 33047f3e84a1SEd Tanous // Option currently returns no systems. TBD 33057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33067f3e84a1SEd Tanous systemName); 33077f3e84a1SEd Tanous return; 33087f3e84a1SEd Tanous } 330922d268cbSEd Tanous if (systemName != "system") 331022d268cbSEd Tanous { 331122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 331222d268cbSEd Tanous systemName); 331322d268cbSEd Tanous return; 331422d268cbSEd Tanous } 33155b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 33165e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3317cb13a392SEd Tanous const std::string&) { 33185b61b5e8SJason M. Bills if (ec) 33195b61b5e8SJason M. Bills { 33205b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 33215b61b5e8SJason M. Bills return; 33225b61b5e8SJason M. Bills } 33235b61b5e8SJason M. Bills messages::success(asyncResp->res); 33245b61b5e8SJason M. Bills }, 3325002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 33267e860f15SJohn Edward Broadbent }); 33275b61b5e8SJason M. Bills } 33285b61b5e8SJason M. Bills 33298d1b46d7Szhanghch05 static void 33308d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 33318d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3332e855dd28SJason M. Bills { 3333043a0536SJohnathan Mantey auto getStoredLogCallback = 3334b9d36b47SEd Tanous [asyncResp, logID, 33355e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3336b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3337e855dd28SJason M. Bills if (ec) 3338e855dd28SJason M. Bills { 333962598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 33401ddcf01aSJason M. Bills if (ec.value() == 33411ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 33421ddcf01aSJason M. Bills { 3343002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33441ddcf01aSJason M. Bills } 33451ddcf01aSJason M. Bills else 33461ddcf01aSJason M. Bills { 3347e855dd28SJason M. Bills messages::internalError(asyncResp->res); 33481ddcf01aSJason M. Bills } 3349e855dd28SJason M. Bills return; 3350e855dd28SJason M. Bills } 3351043a0536SJohnathan Mantey 3352043a0536SJohnathan Mantey std::string timestamp{}; 3353043a0536SJohnathan Mantey std::string filename{}; 3354043a0536SJohnathan Mantey std::string logfile{}; 33552c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3356043a0536SJohnathan Mantey 3357043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3358e855dd28SJason M. Bills { 33599db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3360e855dd28SJason M. Bills return; 3361e855dd28SJason M. Bills } 3362e855dd28SJason M. Bills 3363043a0536SJohnathan Mantey std::string crashdumpURI = 3364e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3365043a0536SJohnathan Mantey logID + "/" + filename; 336684afc48bSJason M. Bills nlohmann::json::object_t logEntry; 33679c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3368ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3369ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3370ef4c65b7SEd Tanous logID); 337184afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 337284afc48bSJason M. Bills logEntry["Id"] = logID; 337384afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 337484afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 337584afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 337684afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 337784afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 33782b20ef6eSJason M. Bills 33792b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 33802b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 33812b20ef6eSJason M. Bills // directly 33822b20ef6eSJason M. Bills if (logEntryJson.is_array()) 33832b20ef6eSJason M. Bills { 33842b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 33852b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 33862b20ef6eSJason M. Bills logEntryJson.size(); 33872b20ef6eSJason M. Bills } 33882b20ef6eSJason M. Bills else 33892b20ef6eSJason M. Bills { 3390d405bb51SJason M. Bills logEntryJson.update(logEntry); 33912b20ef6eSJason M. Bills } 3392e855dd28SJason M. Bills }; 3393d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3394d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3395d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3396d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3397e855dd28SJason M. Bills } 3398e855dd28SJason M. Bills 33997e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 34001da66f75SEd Tanous { 34013946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34023946028dSAppaRao Puli // method for security reasons. 34031da66f75SEd Tanous /** 34041da66f75SEd Tanous * Functions triggers appropriate requests on DBus 34051da66f75SEd Tanous */ 34067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 340722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3408ed398213SEd Tanous // This is incorrect, should be. 3409ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3410432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3411002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3412002d39b4SEd Tanous [&app](const crow::Request& req, 341322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 341422d268cbSEd Tanous const std::string& systemName) { 34153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 341645ca1b86SEd Tanous { 341745ca1b86SEd Tanous return; 341845ca1b86SEd Tanous } 34197f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34207f3e84a1SEd Tanous { 34217f3e84a1SEd Tanous // Option currently returns no systems. TBD 34227f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34237f3e84a1SEd Tanous systemName); 34247f3e84a1SEd Tanous return; 34257f3e84a1SEd Tanous } 342622d268cbSEd Tanous if (systemName != "system") 342722d268cbSEd Tanous { 342822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 342922d268cbSEd Tanous systemName); 343022d268cbSEd Tanous return; 343122d268cbSEd Tanous } 343222d268cbSEd Tanous 34337a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 34347a1dbc48SGeorge Liu crashdumpInterface}; 34357a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 34367a1dbc48SGeorge Liu "/", 0, interfaces, 34377a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 34382b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 34391da66f75SEd Tanous if (ec) 34401da66f75SEd Tanous { 34411da66f75SEd Tanous if (ec.value() != 34421da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 34431da66f75SEd Tanous { 344462598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 344562598e31SEd Tanous ec.message()); 3446f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34471da66f75SEd Tanous return; 34481da66f75SEd Tanous } 34491da66f75SEd Tanous } 3450e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 34511da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 34520f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3453424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3454002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3455e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3456424c4176SJason M. Bills "Collection of Crashdump Entries"; 3457002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3458a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 34592b20ef6eSJason M. Bills 34602b20ef6eSJason M. Bills for (const std::string& path : resp) 34611da66f75SEd Tanous { 34622b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3463e855dd28SJason M. Bills // Get the log ID 34642b20ef6eSJason M. Bills std::string logID = objPath.filename(); 34652b20ef6eSJason M. Bills if (logID.empty()) 34661da66f75SEd Tanous { 3467e855dd28SJason M. Bills continue; 34681da66f75SEd Tanous } 3469e855dd28SJason M. Bills // Add the log entry to the array 34702b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 34712b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 34721da66f75SEd Tanous } 34737a1dbc48SGeorge Liu }); 34747e860f15SJohn Edward Broadbent }); 34751da66f75SEd Tanous } 34761da66f75SEd Tanous 34777e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 34781da66f75SEd Tanous { 34793946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34803946028dSAppaRao Puli // method for security reasons. 34811da66f75SEd Tanous 34827e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 348322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3484ed398213SEd Tanous // this is incorrect, should be 3485ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3486432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 34877e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 348845ca1b86SEd Tanous [&app](const crow::Request& req, 34897e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 349022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 34913ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 349245ca1b86SEd Tanous { 349345ca1b86SEd Tanous return; 349445ca1b86SEd Tanous } 34957f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34967f3e84a1SEd Tanous { 34977f3e84a1SEd Tanous // Option currently returns no systems. TBD 34987f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34997f3e84a1SEd Tanous systemName); 35007f3e84a1SEd Tanous return; 35017f3e84a1SEd Tanous } 350222d268cbSEd Tanous if (systemName != "system") 350322d268cbSEd Tanous { 350422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 350522d268cbSEd Tanous systemName); 350622d268cbSEd Tanous return; 350722d268cbSEd Tanous } 35087e860f15SJohn Edward Broadbent const std::string& logID = param; 3509e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 35107e860f15SJohn Edward Broadbent }); 3511e855dd28SJason M. Bills } 3512e855dd28SJason M. Bills 35137e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3514e855dd28SJason M. Bills { 35153946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 35163946028dSAppaRao Puli // method for security reasons. 35177e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 35187e860f15SJohn Edward Broadbent app, 351922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3520ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 35217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3522a4ce114aSNan Zhou [](const crow::Request& req, 35237e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352422d268cbSEd Tanous const std::string& systemName, const std::string& logID, 352522d268cbSEd Tanous const std::string& fileName) { 35262a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 35272a9beeedSShounak Mitra // Redfish resource. 352822d268cbSEd Tanous 35297f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35307f3e84a1SEd Tanous { 35317f3e84a1SEd Tanous // Option currently returns no systems. TBD 35327f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35337f3e84a1SEd Tanous systemName); 35347f3e84a1SEd Tanous return; 35357f3e84a1SEd Tanous } 353622d268cbSEd Tanous if (systemName != "system") 353722d268cbSEd Tanous { 353822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 353922d268cbSEd Tanous systemName); 354022d268cbSEd Tanous return; 354122d268cbSEd Tanous } 354222d268cbSEd Tanous 3543043a0536SJohnathan Mantey auto getStoredLogCallback = 354439662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 35455e7e2dc5SEd Tanous const boost::system::error_code& ec, 3546002d39b4SEd Tanous const std::vector< 3547002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 35487e860f15SJohn Edward Broadbent resp) { 35491da66f75SEd Tanous if (ec) 35501da66f75SEd Tanous { 355162598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3552f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35531da66f75SEd Tanous return; 35541da66f75SEd Tanous } 3555e855dd28SJason M. Bills 3556043a0536SJohnathan Mantey std::string dbusFilename{}; 3557043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3558043a0536SJohnathan Mantey std::string dbusFilepath{}; 3559043a0536SJohnathan Mantey 3560002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3561002d39b4SEd Tanous dbusFilepath); 3562043a0536SJohnathan Mantey 3563043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3564043a0536SJohnathan Mantey dbusFilepath.empty()) 35651da66f75SEd Tanous { 35669db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 35671da66f75SEd Tanous return; 35681da66f75SEd Tanous } 3569e855dd28SJason M. Bills 3570043a0536SJohnathan Mantey // Verify the file name parameter is correct 3571043a0536SJohnathan Mantey if (fileName != dbusFilename) 3572043a0536SJohnathan Mantey { 35739db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3574043a0536SJohnathan Mantey return; 3575043a0536SJohnathan Mantey } 3576043a0536SJohnathan Mantey 357727b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3578043a0536SJohnathan Mantey { 35799db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3580043a0536SJohnathan Mantey return; 3581043a0536SJohnathan Mantey } 3582043a0536SJohnathan Mantey 35837e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 35847e860f15SJohn Edward Broadbent // from a browser 3585d9f6c621SEd Tanous asyncResp->res.addHeader( 3586d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 35871da66f75SEd Tanous }; 3588d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3589d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3590d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3591d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 35927e860f15SJohn Edward Broadbent }); 35931da66f75SEd Tanous } 35941da66f75SEd Tanous 3595c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3596c5a4c82aSJason M. Bills { 3597c5a4c82aSJason M. Bills onDemand, 3598c5a4c82aSJason M. Bills telemetry, 3599c5a4c82aSJason M. Bills invalid, 3600c5a4c82aSJason M. Bills }; 3601c5a4c82aSJason M. Bills 360226ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3603c5a4c82aSJason M. Bills { 3604c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3605c5a4c82aSJason M. Bills { 3606c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3607c5a4c82aSJason M. Bills } 3608c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3609c5a4c82aSJason M. Bills { 3610c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3611c5a4c82aSJason M. Bills } 3612c5a4c82aSJason M. Bills 3613c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3614c5a4c82aSJason M. Bills } 3615c5a4c82aSJason M. Bills 36167e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 36171da66f75SEd Tanous { 36183946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 36193946028dSAppaRao Puli // method for security reasons. 36200fda0f12SGeorge Liu BMCWEB_ROUTE( 36210fda0f12SGeorge Liu app, 362222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3623ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3624ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3625432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3626002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3627002d39b4SEd Tanous [&app](const crow::Request& req, 362822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 362922d268cbSEd Tanous const std::string& systemName) { 36303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 363145ca1b86SEd Tanous { 363245ca1b86SEd Tanous return; 363345ca1b86SEd Tanous } 363422d268cbSEd Tanous 36357f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 36367f3e84a1SEd Tanous { 36377f3e84a1SEd Tanous // Option currently returns no systems. TBD 36387f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36397f3e84a1SEd Tanous systemName); 36407f3e84a1SEd Tanous return; 36417f3e84a1SEd Tanous } 364222d268cbSEd Tanous if (systemName != "system") 364322d268cbSEd Tanous { 364422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 364522d268cbSEd Tanous systemName); 364622d268cbSEd Tanous return; 364722d268cbSEd Tanous } 364822d268cbSEd Tanous 36498e6c099aSJason M. Bills std::string diagnosticDataType; 36508e6c099aSJason M. Bills std::string oemDiagnosticDataType; 365115ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3652002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3653002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 36548e6c099aSJason M. Bills { 36558e6c099aSJason M. Bills return; 36568e6c099aSJason M. Bills } 36578e6c099aSJason M. Bills 36588e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 36598e6c099aSJason M. Bills { 366062598e31SEd Tanous BMCWEB_LOG_ERROR( 366162598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 36628e6c099aSJason M. Bills messages::actionParameterValueFormatError( 36638e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 36648e6c099aSJason M. Bills "CollectDiagnosticData"); 36658e6c099aSJason M. Bills return; 36668e6c099aSJason M. Bills } 36678e6c099aSJason M. Bills 3668c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3669c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3670c5a4c82aSJason M. Bills 3671c5a4c82aSJason M. Bills std::string iface; 3672c5a4c82aSJason M. Bills std::string method; 3673c5a4c82aSJason M. Bills std::string taskMatchStr; 3674c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3675c5a4c82aSJason M. Bills { 3676c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3677c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3678c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3679c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3680c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3681c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3682c5a4c82aSJason M. Bills } 3683c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3684c5a4c82aSJason M. Bills { 3685c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3686c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3687c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3688c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3689c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3690c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3691c5a4c82aSJason M. Bills } 3692c5a4c82aSJason M. Bills else 3693c5a4c82aSJason M. Bills { 369462598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 369562598e31SEd Tanous oemDiagnosticDataType); 3696c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3697002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3698002d39b4SEd Tanous "CollectDiagnosticData"); 3699c5a4c82aSJason M. Bills return; 3700c5a4c82aSJason M. Bills } 3701c5a4c82aSJason M. Bills 3702c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3703c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 37045e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 370598be3e39SEd Tanous const std::string&) mutable { 37061da66f75SEd Tanous if (ec) 37071da66f75SEd Tanous { 3708002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 37091da66f75SEd Tanous { 3710f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 37111da66f75SEd Tanous } 37124363d3b2SJason M. Bills else if (ec.value() == 37134363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 37144363d3b2SJason M. Bills { 3715002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3716002d39b4SEd Tanous "60"); 37174363d3b2SJason M. Bills } 37181da66f75SEd Tanous else 37191da66f75SEd Tanous { 3720f12894f8SJason M. Bills messages::internalError(asyncResp->res); 37211da66f75SEd Tanous } 37221da66f75SEd Tanous return; 37231da66f75SEd Tanous } 3724002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 37258b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3726002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 37278b24275dSEd Tanous if (!ec2) 372866afe4faSJames Feist { 3729002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3730e5d5006bSJames Feist std::to_string(taskData->index))); 3731831d6b09SJames Feist taskData->state = "Completed"; 373266afe4faSJames Feist } 373332898ceaSJames Feist return task::completed; 373466afe4faSJames Feist }, 3735c5a4c82aSJason M. Bills taskMatchStr); 3736c5a4c82aSJason M. Bills 373746229577SJames Feist task->startTimer(std::chrono::minutes(5)); 373846229577SJames Feist task->populateResp(asyncResp->res); 373998be3e39SEd Tanous task->payload.emplace(std::move(payload)); 37401da66f75SEd Tanous }; 37418e6c099aSJason M. Bills 37421da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3743002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3744002d39b4SEd Tanous iface, method); 37457e860f15SJohn Edward Broadbent }); 37466eda7685SKenny L. Ku } 37476eda7685SKenny L. Ku 3748cb92c03bSAndrew Geissler /** 3749cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3750cb92c03bSAndrew Geissler */ 37517e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3752cb92c03bSAndrew Geissler { 3753cb92c03bSAndrew Geissler /** 3754cb92c03bSAndrew Geissler * Function handles POST method request. 3755cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3756cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3757cb92c03bSAndrew Geissler */ 37587e860f15SJohn Edward Broadbent 37590fda0f12SGeorge Liu BMCWEB_ROUTE( 37600fda0f12SGeorge Liu app, 376122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3762ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 37637e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 376445ca1b86SEd Tanous [&app](const crow::Request& req, 376522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 376622d268cbSEd Tanous const std::string& systemName) { 37673ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 376845ca1b86SEd Tanous { 376945ca1b86SEd Tanous return; 377045ca1b86SEd Tanous } 37717f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37727f3e84a1SEd Tanous { 37737f3e84a1SEd Tanous // Option currently returns no systems. TBD 37747f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37757f3e84a1SEd Tanous systemName); 37767f3e84a1SEd Tanous return; 37777f3e84a1SEd Tanous } 377822d268cbSEd Tanous if (systemName != "system") 377922d268cbSEd Tanous { 378022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 378122d268cbSEd Tanous systemName); 378222d268cbSEd Tanous return; 378322d268cbSEd Tanous } 378462598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3785cb92c03bSAndrew Geissler 3786cb92c03bSAndrew Geissler // Process response from Logging service. 37875e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 378862598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3789cb92c03bSAndrew Geissler if (ec) 3790cb92c03bSAndrew Geissler { 3791cb92c03bSAndrew Geissler // TODO Handle for specific error code 379262598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3793cb92c03bSAndrew Geissler asyncResp->res.result( 3794cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3795cb92c03bSAndrew Geissler return; 3796cb92c03bSAndrew Geissler } 3797cb92c03bSAndrew Geissler 3798002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3799cb92c03bSAndrew Geissler }; 3800cb92c03bSAndrew Geissler 3801cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3802cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 38032c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3804cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3805cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 38067e860f15SJohn Edward Broadbent }); 3807cb92c03bSAndrew Geissler } 3808a3316fc6SZhikuiRen 3809a3316fc6SZhikuiRen /**************************************************** 3810a3316fc6SZhikuiRen * Redfish PostCode interfaces 3811a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3812a3316fc6SZhikuiRen ******************************************************/ 38137e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3814a3316fc6SZhikuiRen { 381522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3816ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3817002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3818002d39b4SEd Tanous [&app](const crow::Request& req, 381922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 382022d268cbSEd Tanous const std::string& systemName) { 38213ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 382245ca1b86SEd Tanous { 382345ca1b86SEd Tanous return; 382445ca1b86SEd Tanous } 38257f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38267f3e84a1SEd Tanous { 38277f3e84a1SEd Tanous // Option currently returns no systems. TBD 38287f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38297f3e84a1SEd Tanous systemName); 38307f3e84a1SEd Tanous return; 38317f3e84a1SEd Tanous } 383222d268cbSEd Tanous if (systemName != "system") 383322d268cbSEd Tanous { 383422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 383522d268cbSEd Tanous systemName); 383622d268cbSEd Tanous return; 383722d268cbSEd Tanous } 38381476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 38391476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 38401476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3841b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 38421476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 38431476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3844ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 38451476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 38461476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 38471476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 38487c8c4058STejas Patil 38497c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 38502b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 38510fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 38527c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 38537c8c4058STejas Patil redfishDateTimeOffset.second; 38547c8c4058STejas Patil 3855a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 38567e860f15SJohn Edward Broadbent {"target", 38570fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 38587e860f15SJohn Edward Broadbent }); 3859a3316fc6SZhikuiRen } 3860a3316fc6SZhikuiRen 38617e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3862a3316fc6SZhikuiRen { 38630fda0f12SGeorge Liu BMCWEB_ROUTE( 38640fda0f12SGeorge Liu app, 386522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3866ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3867ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3868432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 38697e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 387045ca1b86SEd Tanous [&app](const crow::Request& req, 387122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 387222d268cbSEd Tanous const std::string& systemName) { 38733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 387445ca1b86SEd Tanous { 387545ca1b86SEd Tanous return; 387645ca1b86SEd Tanous } 38777f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38787f3e84a1SEd Tanous { 38797f3e84a1SEd Tanous // Option currently returns no systems. TBD 38807f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38817f3e84a1SEd Tanous systemName); 38827f3e84a1SEd Tanous return; 38837f3e84a1SEd Tanous } 388422d268cbSEd Tanous if (systemName != "system") 388522d268cbSEd Tanous { 388622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 388722d268cbSEd Tanous systemName); 388822d268cbSEd Tanous return; 388922d268cbSEd Tanous } 389062598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3891a3316fc6SZhikuiRen 3892a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3893a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 38945e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3895a3316fc6SZhikuiRen if (ec) 3896a3316fc6SZhikuiRen { 3897a3316fc6SZhikuiRen // TODO Handle for specific error code 389862598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 389962598e31SEd Tanous ec); 3900002d39b4SEd Tanous asyncResp->res.result( 3901002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3902a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3903a3316fc6SZhikuiRen return; 3904a3316fc6SZhikuiRen } 390518fc70c0STony Lee messages::success(asyncResp->res); 3906a3316fc6SZhikuiRen }, 390715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 390815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3909a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 39107e860f15SJohn Edward Broadbent }); 3911a3316fc6SZhikuiRen } 3912a3316fc6SZhikuiRen 39136f284d24SJiaqing Zhao /** 39146f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 39156f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 39166f284d24SJiaqing Zhao * 39176f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 39186f284d24SJiaqing Zhao * @param[out] currentValue Current value 39196f284d24SJiaqing Zhao * @param[out] index Index value 39206f284d24SJiaqing Zhao * 39216f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 39226f284d24SJiaqing Zhao */ 3923df254f2cSEd Tanous inline bool parsePostCode(const std::string& postCodeID, uint64_t& currentValue, 3924df254f2cSEd Tanous uint16_t& index) 39256f284d24SJiaqing Zhao { 39266f284d24SJiaqing Zhao std::vector<std::string> split; 392750ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 39286f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 39296f284d24SJiaqing Zhao { 39306f284d24SJiaqing Zhao return false; 39316f284d24SJiaqing Zhao } 39326f284d24SJiaqing Zhao 393384396af9SPatrick Williams auto start = std::next(split[0].begin()); 393484396af9SPatrick Williams auto end = split[0].end(); 393584396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 39366f284d24SJiaqing Zhao 393784396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 39386f284d24SJiaqing Zhao { 39396f284d24SJiaqing Zhao return false; 39406f284d24SJiaqing Zhao } 39416f284d24SJiaqing Zhao 394284396af9SPatrick Williams start = split[1].begin(); 394384396af9SPatrick Williams end = split[1].end(); 39446f284d24SJiaqing Zhao 394584396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 39466f284d24SJiaqing Zhao 394784396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 39486f284d24SJiaqing Zhao } 39496f284d24SJiaqing Zhao 39506f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3951ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39526c9a279eSManojkiran Eda const boost::container::flat_map< 39536c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3954a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3955a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3956a3316fc6SZhikuiRen { 3957a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3958fffb8c1fSEd Tanous const registries::Message* message = 3959fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3960a3316fc6SZhikuiRen 3961a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3962a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 39636c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 39646c9a279eSManojkiran Eda code : postcode) 3965a3316fc6SZhikuiRen { 3966a3316fc6SZhikuiRen currentCodeIndex++; 3967a3316fc6SZhikuiRen std::string postcodeEntryID = 3968a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3969a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3970a3316fc6SZhikuiRen 3971a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3972a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3973a3316fc6SZhikuiRen 3974a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3975a3316fc6SZhikuiRen { // already incremented 3976a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3977a3316fc6SZhikuiRen } 3978a3316fc6SZhikuiRen else 3979a3316fc6SZhikuiRen { 3980a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3981a3316fc6SZhikuiRen } 3982a3316fc6SZhikuiRen 3983a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 3984a3316fc6SZhikuiRen // not fall between top and skip 3985a3316fc6SZhikuiRen if ((codeIndex == 0) && 3986a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 3987a3316fc6SZhikuiRen { 3988a3316fc6SZhikuiRen continue; 3989a3316fc6SZhikuiRen } 3990a3316fc6SZhikuiRen 39914e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 3992a3316fc6SZhikuiRen // currentIndex 3993a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 3994a3316fc6SZhikuiRen { 3995a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 3996a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 3997a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 3998a3316fc6SZhikuiRen continue; 3999a3316fc6SZhikuiRen } 4000a3316fc6SZhikuiRen 4001a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 4002a3316fc6SZhikuiRen // index 4003a3316fc6SZhikuiRen 4004a3316fc6SZhikuiRen // Get the Created time from the timestamp 4005a3316fc6SZhikuiRen std::string entryTimeStr; 40062a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 4007a3316fc6SZhikuiRen 4008a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 4009a3316fc6SZhikuiRen std::ostringstream hexCode; 4010a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 40116c9a279eSManojkiran Eda << std::get<0>(code.second); 4012a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 4013a3316fc6SZhikuiRen // Set Fixed -Point Notation 4014a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 4015a3316fc6SZhikuiRen // Set precision to 4 digits 4016a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 4017a3316fc6SZhikuiRen // Add double to stream 4018a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 4019a3316fc6SZhikuiRen 40201e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 40211e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 40221e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 4023a3316fc6SZhikuiRen 40241e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 40251e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 40261e6deaf6SEd Tanous 40271e6deaf6SEd Tanous std::string msg = 40281e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 40291e6deaf6SEd Tanous if (msg.empty()) 4030a3316fc6SZhikuiRen { 40311e6deaf6SEd Tanous messages::internalError(asyncResp->res); 40321e6deaf6SEd Tanous return false; 4033a3316fc6SZhikuiRen } 4034a3316fc6SZhikuiRen 4035d4342a92STim Lee // Get Severity template from message registry 4036d4342a92STim Lee std::string severity; 4037d4342a92STim Lee if (message != nullptr) 4038d4342a92STim Lee { 40395f2b84eeSEd Tanous severity = message->messageSeverity; 4040d4342a92STim Lee } 4041d4342a92STim Lee 40426f284d24SJiaqing Zhao // Format entry 40436f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 40449c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4045ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 4046ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 4047ef4c65b7SEd Tanous postcodeEntryID); 404884afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 404984afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 405084afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 405184afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 40521e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 405384afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 405484afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 405584afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 4056647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 4057647b3cdcSGeorge Liu { 4058647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 4059647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 4060647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 4061647b3cdcSGeorge Liu } 40626f284d24SJiaqing Zhao 40636f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 40646f284d24SJiaqing Zhao // that entry in this case 40656f284d24SJiaqing Zhao if (codeIndex != 0) 40666f284d24SJiaqing Zhao { 4067ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 40686f284d24SJiaqing Zhao return true; 4069a3316fc6SZhikuiRen } 40706f284d24SJiaqing Zhao 4071ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 4072b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 40736f284d24SJiaqing Zhao } 40746f284d24SJiaqing Zhao 40756f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 40766f284d24SJiaqing Zhao return false; 4077a3316fc6SZhikuiRen } 4078a3316fc6SZhikuiRen 4079ac106bf6SEd Tanous static void 4080ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40816f284d24SJiaqing Zhao const std::string& entryId) 4082a3316fc6SZhikuiRen { 40836f284d24SJiaqing Zhao uint16_t bootIndex = 0; 40846f284d24SJiaqing Zhao uint64_t codeIndex = 0; 40856f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 40866f284d24SJiaqing Zhao { 40876f284d24SJiaqing Zhao // Requested ID was not found 4088ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40896f284d24SJiaqing Zhao return; 40906f284d24SJiaqing Zhao } 40916f284d24SJiaqing Zhao 40926f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 40936f284d24SJiaqing Zhao { 40946f284d24SJiaqing Zhao // 0 is an invalid index 4095ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 40966f284d24SJiaqing Zhao return; 40976f284d24SJiaqing Zhao } 40986f284d24SJiaqing Zhao 4099a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4100ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 41015e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 41026c9a279eSManojkiran Eda const boost::container::flat_map< 41036c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41046c9a279eSManojkiran Eda postcode) { 4105a3316fc6SZhikuiRen if (ec) 4106a3316fc6SZhikuiRen { 410762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4108ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4109a3316fc6SZhikuiRen return; 4110a3316fc6SZhikuiRen } 4111a3316fc6SZhikuiRen 4112a3316fc6SZhikuiRen if (postcode.empty()) 4113a3316fc6SZhikuiRen { 4114ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 4115a3316fc6SZhikuiRen return; 4116a3316fc6SZhikuiRen } 4117a3316fc6SZhikuiRen 4118ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 41196f284d24SJiaqing Zhao { 4120ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41216f284d24SJiaqing Zhao return; 41226f284d24SJiaqing Zhao } 4123a3316fc6SZhikuiRen }, 412415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 412515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4126a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4127a3316fc6SZhikuiRen bootIndex); 4128a3316fc6SZhikuiRen } 4129a3316fc6SZhikuiRen 4130ac106bf6SEd Tanous static void 4131ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4132ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4133ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4134a3316fc6SZhikuiRen { 4135a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4136ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 41375e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 41386c9a279eSManojkiran Eda const boost::container::flat_map< 41396c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41406c9a279eSManojkiran Eda postcode) { 4141a3316fc6SZhikuiRen if (ec) 4142a3316fc6SZhikuiRen { 414362598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4144ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4145a3316fc6SZhikuiRen return; 4146a3316fc6SZhikuiRen } 4147a3316fc6SZhikuiRen 4148a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4149a3316fc6SZhikuiRen if (!postcode.empty()) 4150a3316fc6SZhikuiRen { 4151a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 41523648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4153a3316fc6SZhikuiRen { 415489492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 415589492a15SPatrick Williams entryCount) - 41563648c8beSEd Tanous entryCount; 4157a3316fc6SZhikuiRen uint64_t thisBootTop = 41583648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 41593648c8beSEd Tanous entryCount; 4160a3316fc6SZhikuiRen 4161ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4162ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4163a3316fc6SZhikuiRen } 4164ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4165a3316fc6SZhikuiRen } 4166a3316fc6SZhikuiRen 4167a3316fc6SZhikuiRen // continue to previous bootIndex 4168a3316fc6SZhikuiRen if (bootIndex < bootCount) 4169a3316fc6SZhikuiRen { 4170ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4171a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4172a3316fc6SZhikuiRen } 417381584abeSJiaqing Zhao else if (skip + top < endCount) 4174a3316fc6SZhikuiRen { 4175ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 41760fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 4177a3316fc6SZhikuiRen std::to_string(skip + top); 4178a3316fc6SZhikuiRen } 4179a3316fc6SZhikuiRen }, 418015124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 418115124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4182a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4183a3316fc6SZhikuiRen bootIndex); 4184a3316fc6SZhikuiRen } 4185a3316fc6SZhikuiRen 41868d1b46d7Szhanghch05 static void 4187ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 41883648c8beSEd Tanous size_t skip, size_t top) 4189a3316fc6SZhikuiRen { 4190a3316fc6SZhikuiRen uint64_t entryCount = 0; 41911e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 41921e1e598dSJonathan Doman *crow::connections::systemBus, 41931e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 41941e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 41951e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4196ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 41971e1e598dSJonathan Doman const uint16_t bootCount) { 4198a3316fc6SZhikuiRen if (ec) 4199a3316fc6SZhikuiRen { 420062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4201ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4202a3316fc6SZhikuiRen return; 4203a3316fc6SZhikuiRen } 4204ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 42051e1e598dSJonathan Doman }); 4206a3316fc6SZhikuiRen } 4207a3316fc6SZhikuiRen 42087e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4209a3316fc6SZhikuiRen { 42107e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 421122d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4212ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 42137e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 421445ca1b86SEd Tanous [&app](const crow::Request& req, 421522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 421622d268cbSEd Tanous const std::string& systemName) { 4217c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4218c937d2bfSEd Tanous .canDelegateTop = true, 4219c937d2bfSEd Tanous .canDelegateSkip = true, 4220c937d2bfSEd Tanous }; 4221c937d2bfSEd Tanous query_param::Query delegatedQuery; 4222c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 42233ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 422445ca1b86SEd Tanous { 422545ca1b86SEd Tanous return; 422645ca1b86SEd Tanous } 42277f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42287f3e84a1SEd Tanous { 42297f3e84a1SEd Tanous // Option currently returns no systems. TBD 42307f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42317f3e84a1SEd Tanous systemName); 42327f3e84a1SEd Tanous return; 42337f3e84a1SEd Tanous } 423422d268cbSEd Tanous 423522d268cbSEd Tanous if (systemName != "system") 423622d268cbSEd Tanous { 423722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 423822d268cbSEd Tanous systemName); 423922d268cbSEd Tanous return; 424022d268cbSEd Tanous } 4241a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4242a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4243a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4244a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4245a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4246a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4247a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4248a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4249a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 42503648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 42515143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 42523648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 42537e860f15SJohn Edward Broadbent }); 4254a3316fc6SZhikuiRen } 4255a3316fc6SZhikuiRen 4256647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4257647b3cdcSGeorge Liu { 42580fda0f12SGeorge Liu BMCWEB_ROUTE( 42590fda0f12SGeorge Liu app, 426022d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4261647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4262647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 426345ca1b86SEd Tanous [&app](const crow::Request& req, 4264647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 426522d268cbSEd Tanous const std::string& systemName, 4266647b3cdcSGeorge Liu const std::string& postCodeID) { 42673ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 426845ca1b86SEd Tanous { 426945ca1b86SEd Tanous return; 427045ca1b86SEd Tanous } 427172e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 427299351cd8SEd Tanous req.getHeaderValue("Accept"), 42734a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4274647b3cdcSGeorge Liu { 4275002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4276647b3cdcSGeorge Liu return; 4277647b3cdcSGeorge Liu } 42787f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42797f3e84a1SEd Tanous { 42807f3e84a1SEd Tanous // Option currently returns no systems. TBD 42817f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42827f3e84a1SEd Tanous systemName); 42837f3e84a1SEd Tanous return; 42847f3e84a1SEd Tanous } 428522d268cbSEd Tanous if (systemName != "system") 428622d268cbSEd Tanous { 428722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 428822d268cbSEd Tanous systemName); 428922d268cbSEd Tanous return; 429022d268cbSEd Tanous } 4291647b3cdcSGeorge Liu 4292647b3cdcSGeorge Liu uint64_t currentValue = 0; 4293647b3cdcSGeorge Liu uint16_t index = 0; 4294647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4295647b3cdcSGeorge Liu { 4296002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4297647b3cdcSGeorge Liu return; 4298647b3cdcSGeorge Liu } 4299647b3cdcSGeorge Liu 4300647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4301647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 43025e7e2dc5SEd Tanous const boost::system::error_code& ec, 4303002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4304002d39b4SEd Tanous postcodes) { 4305647b3cdcSGeorge Liu if (ec.value() == EBADR) 4306647b3cdcSGeorge Liu { 4307002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4308002d39b4SEd Tanous postCodeID); 4309647b3cdcSGeorge Liu return; 4310647b3cdcSGeorge Liu } 4311647b3cdcSGeorge Liu if (ec) 4312647b3cdcSGeorge Liu { 431362598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4314647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4315647b3cdcSGeorge Liu return; 4316647b3cdcSGeorge Liu } 4317647b3cdcSGeorge Liu 4318647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4319002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4320647b3cdcSGeorge Liu { 432162598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4322002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4323002d39b4SEd Tanous postCodeID); 4324647b3cdcSGeorge Liu return; 4325647b3cdcSGeorge Liu } 4326647b3cdcSGeorge Liu 43279eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 432846ff87baSEd Tanous if (c.empty()) 4329647b3cdcSGeorge Liu { 433062598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4331002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4332002d39b4SEd Tanous postCodeID); 4333647b3cdcSGeorge Liu return; 4334647b3cdcSGeorge Liu } 433546ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 433646ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 433746ff87baSEd Tanous std::string_view strData(d, c.size()); 4338647b3cdcSGeorge Liu 4339d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4340647b3cdcSGeorge Liu "application/octet-stream"); 4341d9f6c621SEd Tanous asyncResp->res.addHeader( 4342d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 434327b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4344647b3cdcSGeorge Liu }, 4345647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4346647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4347002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4348647b3cdcSGeorge Liu }); 4349647b3cdcSGeorge Liu } 4350647b3cdcSGeorge Liu 43517e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4352a3316fc6SZhikuiRen { 43537e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 435422d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4355ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 43567e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 435745ca1b86SEd Tanous [&app](const crow::Request& req, 43587e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 435922d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 43603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 436145ca1b86SEd Tanous { 436245ca1b86SEd Tanous return; 436345ca1b86SEd Tanous } 43647f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 43657f3e84a1SEd Tanous { 43667f3e84a1SEd Tanous // Option currently returns no systems. TBD 43677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 43687f3e84a1SEd Tanous systemName); 43697f3e84a1SEd Tanous return; 43707f3e84a1SEd Tanous } 437122d268cbSEd Tanous if (systemName != "system") 437222d268cbSEd Tanous { 437322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 437422d268cbSEd Tanous systemName); 437522d268cbSEd Tanous return; 437622d268cbSEd Tanous } 437722d268cbSEd Tanous 43786f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 43797e860f15SJohn Edward Broadbent }); 4380a3316fc6SZhikuiRen } 4381a3316fc6SZhikuiRen 43821da66f75SEd Tanous } // namespace redfish 4383