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 34*75e8e218SMyung 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 399896eaedSEd Tanous #include <boost/algorithm/string/case_conv.hpp> 4011ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 41400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp> 424851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp> 4307c8c20dSEd Tanous #include <boost/beast/http/verb.hpp> 441da66f75SEd Tanous #include <boost/container/flat_map.hpp> 451ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp> 46ef4c65b7SEd Tanous #include <boost/url/format.hpp> 47d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 48d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 491214b7e7SGunnar Mills 507a1dbc48SGeorge Liu #include <array> 51647b3cdcSGeorge Liu #include <charconv> 524418c7f0SJames Feist #include <filesystem> 5375710de2SXiaochao Ma #include <optional> 543544d2a7SEd Tanous #include <ranges> 5526702d01SEd Tanous #include <span> 56cd225da8SJason M. Bills #include <string_view> 57abf2add6SEd Tanous #include <variant> 581da66f75SEd Tanous 591da66f75SEd Tanous namespace redfish 601da66f75SEd Tanous { 611da66f75SEd Tanous 6289492a15SPatrick Williams constexpr const char* crashdumpObject = "com.intel.crashdump"; 6389492a15SPatrick Williams constexpr const char* crashdumpPath = "/com/intel/crashdump"; 6489492a15SPatrick Williams constexpr const char* crashdumpInterface = "com.intel.crashdump"; 6589492a15SPatrick Williams constexpr const char* deleteAllInterface = 665b61b5e8SJason M. Bills "xyz.openbmc_project.Collection.DeleteAll"; 6789492a15SPatrick Williams constexpr const char* crashdumpOnDemandInterface = 68424c4176SJason M. Bills "com.intel.crashdump.OnDemand"; 6989492a15SPatrick Williams constexpr const char* crashdumpTelemetryInterface = 706eda7685SKenny L. Ku "com.intel.crashdump.Telemetry"; 711da66f75SEd Tanous 728e31778eSAsmitha Karunanithi enum class DumpCreationProgress 738e31778eSAsmitha Karunanithi { 748e31778eSAsmitha Karunanithi DUMP_CREATE_SUCCESS, 758e31778eSAsmitha Karunanithi DUMP_CREATE_FAILED, 768e31778eSAsmitha Karunanithi DUMP_CREATE_INPROGRESS 778e31778eSAsmitha Karunanithi }; 788e31778eSAsmitha Karunanithi 79f6150403SJames Feist namespace fs = std::filesystem; 801da66f75SEd Tanous 81cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s) 82cb92c03bSAndrew Geissler { 83d4d25793SEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") || 84d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") || 85d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") || 86d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Error")) 87cb92c03bSAndrew Geissler { 88cb92c03bSAndrew Geissler return "Critical"; 89cb92c03bSAndrew Geissler } 903174e4dfSEd Tanous if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") || 91d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") || 92d4d25793SEd Tanous (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")) 93cb92c03bSAndrew Geissler { 94cb92c03bSAndrew Geissler return "OK"; 95cb92c03bSAndrew Geissler } 963174e4dfSEd Tanous if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning") 97cb92c03bSAndrew Geissler { 98cb92c03bSAndrew Geissler return "Warning"; 99cb92c03bSAndrew Geissler } 100cb92c03bSAndrew Geissler return ""; 101cb92c03bSAndrew Geissler } 102cb92c03bSAndrew Geissler 1039017faf2SAbhishek Patel inline std::optional<bool> getProviderNotifyAction(const std::string& notify) 1049017faf2SAbhishek Patel { 1059017faf2SAbhishek Patel std::optional<bool> notifyAction; 1069017faf2SAbhishek Patel if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify") 1079017faf2SAbhishek Patel { 1089017faf2SAbhishek Patel notifyAction = true; 1099017faf2SAbhishek Patel } 1109017faf2SAbhishek Patel else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit") 1119017faf2SAbhishek Patel { 1129017faf2SAbhishek Patel notifyAction = false; 1139017faf2SAbhishek Patel } 1149017faf2SAbhishek Patel 1159017faf2SAbhishek Patel return notifyAction; 1169017faf2SAbhishek Patel } 1179017faf2SAbhishek Patel 1187e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 11926ccae32SEd Tanous std::string_view field, 12039e77504SEd Tanous std::string_view& contents) 12116428a1aSJason M. Bills { 12216428a1aSJason M. Bills const char* data = nullptr; 12316428a1aSJason M. Bills size_t length = 0; 12416428a1aSJason M. Bills int ret = 0; 12516428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 12646ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 12746ff87baSEd Tanous const void** dataVoid = reinterpret_cast<const void**>(&data); 12846ff87baSEd Tanous 12946ff87baSEd Tanous ret = sd_journal_get_data(journal, field.data(), dataVoid, &length); 13016428a1aSJason M. Bills if (ret < 0) 13116428a1aSJason M. Bills { 13216428a1aSJason M. Bills return ret; 13316428a1aSJason M. Bills } 13439e77504SEd Tanous contents = std::string_view(data, length); 13516428a1aSJason M. Bills // Only use the content after the "=" character. 13681ce609eSEd Tanous contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 13716428a1aSJason M. Bills return ret; 13816428a1aSJason M. Bills } 13916428a1aSJason M. Bills 1407e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal, 14126ccae32SEd Tanous std::string_view field, const int& base, 14226ccae32SEd Tanous long int& contents) 14316428a1aSJason M. Bills { 14416428a1aSJason M. Bills int ret = 0; 14539e77504SEd Tanous std::string_view metadata; 14616428a1aSJason M. Bills // Get the metadata from the requested field of the journal entry 14716428a1aSJason M. Bills ret = getJournalMetadata(journal, field, metadata); 14816428a1aSJason M. Bills if (ret < 0) 14916428a1aSJason M. Bills { 15016428a1aSJason M. Bills return ret; 15116428a1aSJason M. Bills } 152b01bf299SEd Tanous contents = strtol(metadata.data(), nullptr, base); 15316428a1aSJason M. Bills return ret; 15416428a1aSJason M. Bills } 15516428a1aSJason M. Bills 1567e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal, 1577e860f15SJohn Edward Broadbent std::string& entryTimestamp) 158a3316fc6SZhikuiRen { 159a3316fc6SZhikuiRen int ret = 0; 160a3316fc6SZhikuiRen uint64_t timestamp = 0; 161a3316fc6SZhikuiRen ret = sd_journal_get_realtime_usec(journal, ×tamp); 162a3316fc6SZhikuiRen if (ret < 0) 163a3316fc6SZhikuiRen { 16462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 165a3316fc6SZhikuiRen return false; 166a3316fc6SZhikuiRen } 167e645c5e6SKonstantin Aladyshev entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 1689c620e21SAsmitha Karunanithi return true; 169a3316fc6SZhikuiRen } 17050b8a43aSEd Tanous 1717e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID, 172e85d6b16SJason M. Bills const bool firstEntry = true) 17316428a1aSJason M. Bills { 17416428a1aSJason M. Bills int ret = 0; 175*75e8e218SMyung Bae static sd_id128_t prevBootID{}; 17616428a1aSJason M. Bills static uint64_t prevTs = 0; 17716428a1aSJason M. Bills static int index = 0; 178e85d6b16SJason M. Bills if (firstEntry) 179e85d6b16SJason M. Bills { 180*75e8e218SMyung Bae prevBootID = {}; 181e85d6b16SJason M. Bills prevTs = 0; 182e85d6b16SJason M. Bills } 183e85d6b16SJason M. Bills 18416428a1aSJason M. Bills // Get the entry timestamp 18516428a1aSJason M. Bills uint64_t curTs = 0; 186*75e8e218SMyung Bae sd_id128_t curBootID{}; 187*75e8e218SMyung Bae ret = sd_journal_get_monotonic_usec(journal, &curTs, &curBootID); 18816428a1aSJason M. Bills if (ret < 0) 18916428a1aSJason M. Bills { 19062598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret)); 19116428a1aSJason M. Bills return false; 19216428a1aSJason M. Bills } 193*75e8e218SMyung Bae // If the timestamp isn't unique on the same boot, increment the index 194*75e8e218SMyung Bae bool sameBootIDs = sd_id128_equal(curBootID, prevBootID) != 0; 195*75e8e218SMyung Bae if (sameBootIDs && (curTs == prevTs)) 19616428a1aSJason M. Bills { 19716428a1aSJason M. Bills index++; 19816428a1aSJason M. Bills } 19916428a1aSJason M. Bills else 20016428a1aSJason M. Bills { 20116428a1aSJason M. Bills // Otherwise, reset it 20216428a1aSJason M. Bills index = 0; 20316428a1aSJason M. Bills } 204*75e8e218SMyung Bae 205*75e8e218SMyung Bae if (!sameBootIDs) 206*75e8e218SMyung Bae { 207*75e8e218SMyung Bae // Save the bootID 208*75e8e218SMyung Bae prevBootID = curBootID; 209*75e8e218SMyung Bae } 21016428a1aSJason M. Bills // Save the timestamp 21116428a1aSJason M. Bills prevTs = curTs; 21216428a1aSJason M. Bills 213*75e8e218SMyung Bae // make entryID as <bootID>_<timestamp>[_<index>] 214*75e8e218SMyung Bae std::array<char, SD_ID128_STRING_MAX> bootIDStr{}; 215*75e8e218SMyung Bae sd_id128_to_string(curBootID, bootIDStr.data()); 216*75e8e218SMyung Bae entryID = std::format("{}_{}", bootIDStr.data(), curTs); 21716428a1aSJason M. Bills if (index > 0) 21816428a1aSJason M. Bills { 21916428a1aSJason M. Bills entryID += "_" + std::to_string(index); 22016428a1aSJason M. Bills } 22116428a1aSJason M. Bills return true; 22216428a1aSJason M. Bills } 22316428a1aSJason M. Bills 224e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID, 225e85d6b16SJason M. Bills const bool firstEntry = true) 22695820184SJason M. Bills { 227271584abSEd Tanous static time_t prevTs = 0; 22895820184SJason M. Bills static int index = 0; 229e85d6b16SJason M. Bills if (firstEntry) 230e85d6b16SJason M. Bills { 231e85d6b16SJason M. Bills prevTs = 0; 232e85d6b16SJason M. Bills } 233e85d6b16SJason M. Bills 23495820184SJason M. Bills // Get the entry timestamp 235271584abSEd Tanous std::time_t curTs = 0; 23695820184SJason M. Bills std::tm timeStruct = {}; 23795820184SJason M. Bills std::istringstream entryStream(logEntry); 23895820184SJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 23995820184SJason M. Bills { 24095820184SJason M. Bills curTs = std::mktime(&timeStruct); 24195820184SJason M. Bills } 24295820184SJason M. Bills // If the timestamp isn't unique, increment the index 24395820184SJason M. Bills if (curTs == prevTs) 24495820184SJason M. Bills { 24595820184SJason M. Bills index++; 24695820184SJason M. Bills } 24795820184SJason M. Bills else 24895820184SJason M. Bills { 24995820184SJason M. Bills // Otherwise, reset it 25095820184SJason M. Bills index = 0; 25195820184SJason M. Bills } 25295820184SJason M. Bills // Save the timestamp 25395820184SJason M. Bills prevTs = curTs; 25495820184SJason M. Bills 25595820184SJason M. Bills entryID = std::to_string(curTs); 25695820184SJason M. Bills if (index > 0) 25795820184SJason M. Bills { 25895820184SJason M. Bills entryID += "_" + std::to_string(index); 25995820184SJason M. Bills } 26095820184SJason M. Bills return true; 26195820184SJason M. Bills } 26295820184SJason M. Bills 263*75e8e218SMyung Bae // Entry is formed like "BootID_timestamp" or "BootID_timestamp_index" 2647e860f15SJohn Edward Broadbent inline static bool 2658d1b46d7Szhanghch05 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 266*75e8e218SMyung Bae const std::string& entryID, sd_id128_t& bootID, 267*75e8e218SMyung Bae uint64_t& timestamp, uint64_t& index) 26816428a1aSJason M. Bills { 26916428a1aSJason M. Bills if (entryID.empty()) 27016428a1aSJason M. Bills { 27116428a1aSJason M. Bills return false; 27216428a1aSJason M. Bills } 27316428a1aSJason M. Bills 274*75e8e218SMyung Bae // Convert the unique ID back to a bootID + timestamp to find the entry 275*75e8e218SMyung Bae std::string_view entryIDStrView(entryID); 276*75e8e218SMyung Bae auto underscore1Pos = entryIDStrView.find('_'); 277*75e8e218SMyung Bae if (underscore1Pos == std::string_view::npos) 278*75e8e218SMyung Bae { 279*75e8e218SMyung Bae // EntryID has no bootID or timestamp 280*75e8e218SMyung Bae messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 281*75e8e218SMyung Bae return false; 282*75e8e218SMyung Bae } 283*75e8e218SMyung Bae 284*75e8e218SMyung Bae // EntryID has bootID + timestamp 285*75e8e218SMyung Bae 286*75e8e218SMyung Bae // Convert entryIDViewString to BootID 287*75e8e218SMyung Bae // NOTE: bootID string which needs to be null-terminated for 288*75e8e218SMyung Bae // sd_id128_from_string() 289*75e8e218SMyung Bae std::string bootIDStr(entryID, 0, underscore1Pos); 290*75e8e218SMyung Bae if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0) 291*75e8e218SMyung Bae { 292*75e8e218SMyung Bae messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 293*75e8e218SMyung Bae return false; 294*75e8e218SMyung Bae } 295*75e8e218SMyung Bae 296*75e8e218SMyung Bae // Get the timestamp from entryID 297*75e8e218SMyung Bae std::string_view timestampStrView = entryIDStrView; 298*75e8e218SMyung Bae timestampStrView.remove_prefix(underscore1Pos + 1); 299*75e8e218SMyung Bae 300*75e8e218SMyung Bae // Check the index in timestamp 301*75e8e218SMyung Bae auto underscore2Pos = timestampStrView.find('_'); 302*75e8e218SMyung Bae if (underscore2Pos != std::string_view::npos) 30316428a1aSJason M. Bills { 30416428a1aSJason M. Bills // Timestamp has an index 305*75e8e218SMyung Bae timestampStrView.remove_suffix(timestampStrView.size() - 306*75e8e218SMyung Bae underscore2Pos); 307*75e8e218SMyung Bae std::string_view indexStr(timestampStrView); 308*75e8e218SMyung Bae indexStr.remove_prefix(underscore2Pos + 1); 30984396af9SPatrick Williams auto [ptr, ec] = std::from_chars(indexStr.begin(), indexStr.end(), 31084396af9SPatrick Williams index); 311c0bd5e4bSEd Tanous if (ec != std::errc()) 31216428a1aSJason M. Bills { 3139db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 31416428a1aSJason M. Bills return false; 31516428a1aSJason M. Bills } 31616428a1aSJason M. Bills } 317*75e8e218SMyung Bae 318*75e8e218SMyung Bae // Now timestamp has no index 319*75e8e218SMyung Bae auto [ptr, ec] = std::from_chars(timestampStrView.begin(), 320*75e8e218SMyung Bae timestampStrView.end(), timestamp); 321c0bd5e4bSEd Tanous if (ec != std::errc()) 32216428a1aSJason M. Bills { 3239db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 32416428a1aSJason M. Bills return false; 32516428a1aSJason M. Bills } 32616428a1aSJason M. Bills return true; 32716428a1aSJason M. Bills } 32816428a1aSJason M. Bills 32995820184SJason M. Bills static bool 33095820184SJason M. Bills getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles) 33195820184SJason M. Bills { 33295820184SJason M. Bills static const std::filesystem::path redfishLogDir = "/var/log"; 33395820184SJason M. Bills static const std::string redfishLogFilename = "redfish"; 33495820184SJason M. Bills 33595820184SJason M. Bills // Loop through the directory looking for redfish log files 33695820184SJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 33795820184SJason M. Bills std::filesystem::directory_iterator(redfishLogDir)) 33895820184SJason M. Bills { 33995820184SJason M. Bills // If we find a redfish log file, save the path 34095820184SJason M. Bills std::string filename = dirEnt.path().filename(); 34111ba3979SEd Tanous if (filename.starts_with(redfishLogFilename)) 34295820184SJason M. Bills { 34395820184SJason M. Bills redfishLogFiles.emplace_back(redfishLogDir / filename); 34495820184SJason M. Bills } 34595820184SJason M. Bills } 34695820184SJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 34795820184SJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 34895820184SJason M. Bills // can just sort the list to get them in order from newest to oldest 3493544d2a7SEd Tanous std::ranges::sort(redfishLogFiles); 35095820184SJason M. Bills 35195820184SJason M. Bills return !redfishLogFiles.empty(); 35295820184SJason M. Bills } 35395820184SJason M. Bills 35468dd075aSAsmitha Karunanithi inline log_entry::OriginatorTypes 35568dd075aSAsmitha Karunanithi mapDbusOriginatorTypeToRedfish(const std::string& originatorType) 35668dd075aSAsmitha Karunanithi { 35768dd075aSAsmitha Karunanithi if (originatorType == 35868dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client") 35968dd075aSAsmitha Karunanithi { 36068dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Client; 36168dd075aSAsmitha Karunanithi } 36268dd075aSAsmitha Karunanithi if (originatorType == 36368dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal") 36468dd075aSAsmitha Karunanithi { 36568dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Internal; 36668dd075aSAsmitha Karunanithi } 36768dd075aSAsmitha Karunanithi if (originatorType == 36868dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService") 36968dd075aSAsmitha Karunanithi { 37068dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::SupportingService; 37168dd075aSAsmitha Karunanithi } 37268dd075aSAsmitha Karunanithi return log_entry::OriginatorTypes::Invalid; 37368dd075aSAsmitha Karunanithi } 37468dd075aSAsmitha Karunanithi 375aefe3786SClaire Weinan inline void parseDumpEntryFromDbusObject( 3762d613eb6SJiaqing Zhao const dbus::utility::ManagedObjectType::value_type& object, 377c6fecdabSClaire Weinan std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs, 37868dd075aSAsmitha Karunanithi std::string& originatorId, log_entry::OriginatorTypes& originatorType, 379aefe3786SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 380aefe3786SClaire Weinan { 381aefe3786SClaire Weinan for (const auto& interfaceMap : object.second) 382aefe3786SClaire Weinan { 383aefe3786SClaire Weinan if (interfaceMap.first == "xyz.openbmc_project.Common.Progress") 384aefe3786SClaire Weinan { 385aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 386aefe3786SClaire Weinan { 387aefe3786SClaire Weinan if (propertyMap.first == "Status") 388aefe3786SClaire Weinan { 389aefe3786SClaire Weinan const auto* status = 390aefe3786SClaire Weinan std::get_if<std::string>(&propertyMap.second); 391aefe3786SClaire Weinan if (status == nullptr) 392aefe3786SClaire Weinan { 393aefe3786SClaire Weinan messages::internalError(asyncResp->res); 394aefe3786SClaire Weinan break; 395aefe3786SClaire Weinan } 396aefe3786SClaire Weinan dumpStatus = *status; 397aefe3786SClaire Weinan } 398aefe3786SClaire Weinan } 399aefe3786SClaire Weinan } 400aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry") 401aefe3786SClaire Weinan { 402aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 403aefe3786SClaire Weinan { 404aefe3786SClaire Weinan if (propertyMap.first == "Size") 405aefe3786SClaire Weinan { 406aefe3786SClaire Weinan const auto* sizePtr = 407aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 408aefe3786SClaire Weinan if (sizePtr == nullptr) 409aefe3786SClaire Weinan { 410aefe3786SClaire Weinan messages::internalError(asyncResp->res); 411aefe3786SClaire Weinan break; 412aefe3786SClaire Weinan } 413aefe3786SClaire Weinan size = *sizePtr; 414aefe3786SClaire Weinan break; 415aefe3786SClaire Weinan } 416aefe3786SClaire Weinan } 417aefe3786SClaire Weinan } 418aefe3786SClaire Weinan else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime") 419aefe3786SClaire Weinan { 420aefe3786SClaire Weinan for (const auto& propertyMap : interfaceMap.second) 421aefe3786SClaire Weinan { 422aefe3786SClaire Weinan if (propertyMap.first == "Elapsed") 423aefe3786SClaire Weinan { 424aefe3786SClaire Weinan const uint64_t* usecsTimeStamp = 425aefe3786SClaire Weinan std::get_if<uint64_t>(&propertyMap.second); 426aefe3786SClaire Weinan if (usecsTimeStamp == nullptr) 427aefe3786SClaire Weinan { 428aefe3786SClaire Weinan messages::internalError(asyncResp->res); 429aefe3786SClaire Weinan break; 430aefe3786SClaire Weinan } 431c6fecdabSClaire Weinan timestampUs = *usecsTimeStamp; 432aefe3786SClaire Weinan break; 433aefe3786SClaire Weinan } 434aefe3786SClaire Weinan } 435aefe3786SClaire Weinan } 43668dd075aSAsmitha Karunanithi else if (interfaceMap.first == 43768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy") 43868dd075aSAsmitha Karunanithi { 43968dd075aSAsmitha Karunanithi for (const auto& propertyMap : interfaceMap.second) 44068dd075aSAsmitha Karunanithi { 44168dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorId") 44268dd075aSAsmitha Karunanithi { 44368dd075aSAsmitha Karunanithi const std::string* id = 44468dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 44568dd075aSAsmitha Karunanithi if (id == nullptr) 44668dd075aSAsmitha Karunanithi { 44768dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 44868dd075aSAsmitha Karunanithi break; 44968dd075aSAsmitha Karunanithi } 45068dd075aSAsmitha Karunanithi originatorId = *id; 45168dd075aSAsmitha Karunanithi } 45268dd075aSAsmitha Karunanithi 45368dd075aSAsmitha Karunanithi if (propertyMap.first == "OriginatorType") 45468dd075aSAsmitha Karunanithi { 45568dd075aSAsmitha Karunanithi const std::string* type = 45668dd075aSAsmitha Karunanithi std::get_if<std::string>(&propertyMap.second); 45768dd075aSAsmitha Karunanithi if (type == nullptr) 45868dd075aSAsmitha Karunanithi { 45968dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46068dd075aSAsmitha Karunanithi break; 46168dd075aSAsmitha Karunanithi } 46268dd075aSAsmitha Karunanithi 46368dd075aSAsmitha Karunanithi originatorType = mapDbusOriginatorTypeToRedfish(*type); 46468dd075aSAsmitha Karunanithi if (originatorType == log_entry::OriginatorTypes::Invalid) 46568dd075aSAsmitha Karunanithi { 46668dd075aSAsmitha Karunanithi messages::internalError(asyncResp->res); 46768dd075aSAsmitha Karunanithi break; 46868dd075aSAsmitha Karunanithi } 46968dd075aSAsmitha Karunanithi } 47068dd075aSAsmitha Karunanithi } 47168dd075aSAsmitha Karunanithi } 472aefe3786SClaire Weinan } 473aefe3786SClaire Weinan } 474aefe3786SClaire Weinan 47521ab404cSNan Zhou static std::string getDumpEntriesPath(const std::string& dumpType) 476fdd26906SClaire Weinan { 477fdd26906SClaire Weinan std::string entriesPath; 478fdd26906SClaire Weinan 479fdd26906SClaire Weinan if (dumpType == "BMC") 480fdd26906SClaire Weinan { 481fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 482fdd26906SClaire Weinan } 483fdd26906SClaire Weinan else if (dumpType == "FaultLog") 484fdd26906SClaire Weinan { 485fdd26906SClaire Weinan entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/"; 486fdd26906SClaire Weinan } 487fdd26906SClaire Weinan else if (dumpType == "System") 488fdd26906SClaire Weinan { 489fdd26906SClaire Weinan entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 490fdd26906SClaire Weinan } 491fdd26906SClaire Weinan else 492fdd26906SClaire Weinan { 49362598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}", 49462598e31SEd Tanous dumpType); 495fdd26906SClaire Weinan } 496fdd26906SClaire Weinan 497fdd26906SClaire Weinan // Returns empty string on error 498fdd26906SClaire Weinan return entriesPath; 499fdd26906SClaire Weinan } 500fdd26906SClaire Weinan 5018d1b46d7Szhanghch05 inline void 5028d1b46d7Szhanghch05 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5035cb1dd27SAsmitha Karunanithi const std::string& dumpType) 5045cb1dd27SAsmitha Karunanithi { 505fdd26906SClaire Weinan std::string entriesPath = getDumpEntriesPath(dumpType); 506fdd26906SClaire Weinan if (entriesPath.empty()) 5075cb1dd27SAsmitha Karunanithi { 5085cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5095cb1dd27SAsmitha Karunanithi return; 5105cb1dd27SAsmitha Karunanithi } 5115cb1dd27SAsmitha Karunanithi 5125eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/dump"); 5135eb468daSGeorge Liu dbus::utility::getManagedObjects( 5145eb468daSGeorge Liu "xyz.openbmc_project.Dump.Manager", path, 515fdd26906SClaire Weinan [asyncResp, entriesPath, 5165e7e2dc5SEd Tanous dumpType](const boost::system::error_code& ec, 5175eb468daSGeorge Liu const dbus::utility::ManagedObjectType& objects) { 5185cb1dd27SAsmitha Karunanithi if (ec) 5195cb1dd27SAsmitha Karunanithi { 52062598e31SEd Tanous BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec); 5215cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 5225cb1dd27SAsmitha Karunanithi return; 5235cb1dd27SAsmitha Karunanithi } 5245cb1dd27SAsmitha Karunanithi 525fdd26906SClaire Weinan // Remove ending slash 526fdd26906SClaire Weinan std::string odataIdStr = entriesPath; 527fdd26906SClaire Weinan if (!odataIdStr.empty()) 528fdd26906SClaire Weinan { 529fdd26906SClaire Weinan odataIdStr.pop_back(); 530fdd26906SClaire Weinan } 531fdd26906SClaire Weinan 532fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = 533fdd26906SClaire Weinan "#LogEntryCollection.LogEntryCollection"; 534fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr); 535fdd26906SClaire Weinan asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries"; 53689492a15SPatrick Williams asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType + 53789492a15SPatrick Williams " Dump Entries"; 538fdd26906SClaire Weinan 5393544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 540b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 541b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 542002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(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; 643b47452b2SAsmitha Karunanithi std::string dumpEntryPath = 644b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 645002d39b4SEd Tanous std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/"; 646b47452b2SAsmitha Karunanithi 6479eb808c1SEd Tanous for (const auto& objectPath : resp) 6485cb1dd27SAsmitha Karunanithi { 649b47452b2SAsmitha Karunanithi if (objectPath.first.str != dumpEntryPath + entryID) 6505cb1dd27SAsmitha Karunanithi { 6515cb1dd27SAsmitha Karunanithi continue; 6525cb1dd27SAsmitha Karunanithi } 6535cb1dd27SAsmitha Karunanithi 6545cb1dd27SAsmitha Karunanithi foundDumpEntry = true; 655c6fecdabSClaire Weinan uint64_t timestampUs = 0; 6565cb1dd27SAsmitha Karunanithi uint64_t size = 0; 65735440d18SAsmitha Karunanithi std::string dumpStatus; 65868dd075aSAsmitha Karunanithi std::string originatorId; 65968dd075aSAsmitha Karunanithi log_entry::OriginatorTypes originatorType = 66068dd075aSAsmitha Karunanithi log_entry::OriginatorTypes::Internal; 6615cb1dd27SAsmitha Karunanithi 662aefe3786SClaire Weinan parseDumpEntryFromDbusObject(objectPath, dumpStatus, size, 66368dd075aSAsmitha Karunanithi timestampUs, originatorId, 66468dd075aSAsmitha Karunanithi originatorType, asyncResp); 6655cb1dd27SAsmitha Karunanithi 6660fda0f12SGeorge Liu if (dumpStatus != 6670fda0f12SGeorge Liu "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" && 66835440d18SAsmitha Karunanithi !dumpStatus.empty()) 66935440d18SAsmitha Karunanithi { 67035440d18SAsmitha Karunanithi // Dump status is not Complete 67135440d18SAsmitha Karunanithi // return not found until status is changed to Completed 672d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, dumpType + " dump", 673d1bde9e5SKrzysztof Grobelny entryID); 67435440d18SAsmitha Karunanithi return; 67535440d18SAsmitha Karunanithi } 67635440d18SAsmitha Karunanithi 6775cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["@odata.type"] = 67868dd075aSAsmitha Karunanithi "#LogEntry.v1_11_0.LogEntry"; 679fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID; 6805cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Id"] = entryID; 6815cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["EntryType"] = "Event"; 6825cb1dd27SAsmitha Karunanithi asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry"; 683bbd80db8SClaire Weinan asyncResp->res.jsonValue["Created"] = 684bbd80db8SClaire Weinan redfish::time_utils::getDateTimeUintUs(timestampUs); 6855cb1dd27SAsmitha Karunanithi 68668dd075aSAsmitha Karunanithi if (!originatorId.empty()) 68768dd075aSAsmitha Karunanithi { 68868dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["Originator"] = originatorId; 68968dd075aSAsmitha Karunanithi asyncResp->res.jsonValue["OriginatorType"] = originatorType; 69068dd075aSAsmitha Karunanithi } 69168dd075aSAsmitha Karunanithi 6925cb1dd27SAsmitha Karunanithi if (dumpType == "BMC") 6935cb1dd27SAsmitha Karunanithi { 694d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager"; 695d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 696fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 697fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 6985cb1dd27SAsmitha Karunanithi } 6995cb1dd27SAsmitha Karunanithi else if (dumpType == "System") 7005cb1dd27SAsmitha Karunanithi { 701d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM"; 702002d39b4SEd Tanous asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System"; 703d337bb72SAsmitha Karunanithi asyncResp->res.jsonValue["AdditionalDataURI"] = 704fdd26906SClaire Weinan entriesPath + entryID + "/attachment"; 705fdd26906SClaire Weinan asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size; 7065cb1dd27SAsmitha Karunanithi } 7075cb1dd27SAsmitha Karunanithi } 708e05aec50SEd Tanous if (!foundDumpEntry) 709b47452b2SAsmitha Karunanithi { 71062598e31SEd Tanous BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 711b90d14f2SMyung Bae messages::resourceNotFound(asyncResp->res, dumpType + " dump", 712b90d14f2SMyung Bae entryID); 713b47452b2SAsmitha Karunanithi return; 714b47452b2SAsmitha Karunanithi } 7155eb468daSGeorge Liu }); 7165cb1dd27SAsmitha Karunanithi } 7175cb1dd27SAsmitha Karunanithi 7188d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7199878256fSStanley Chu const std::string& entryID, 720b47452b2SAsmitha Karunanithi const std::string& dumpType) 7215cb1dd27SAsmitha Karunanithi { 7225a39f77aSPatrick Williams auto respHandler = [asyncResp, 7235a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 72462598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done"); 7255cb1dd27SAsmitha Karunanithi if (ec) 7265cb1dd27SAsmitha Karunanithi { 7273de8d8baSGeorge Liu if (ec.value() == EBADR) 7283de8d8baSGeorge Liu { 7293de8d8baSGeorge Liu messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 7303de8d8baSGeorge Liu return; 7313de8d8baSGeorge Liu } 73262598e31SEd Tanous BMCWEB_LOG_ERROR( 73362598e31SEd Tanous "Dump (DBus) doDelete respHandler got error {} entryID={}", ec, 73462598e31SEd Tanous entryID); 7355cb1dd27SAsmitha Karunanithi messages::internalError(asyncResp->res); 7365cb1dd27SAsmitha Karunanithi return; 7375cb1dd27SAsmitha Karunanithi } 7385cb1dd27SAsmitha Karunanithi }; 7395cb1dd27SAsmitha Karunanithi crow::connections::systemBus->async_method_call( 7405cb1dd27SAsmitha Karunanithi respHandler, "xyz.openbmc_project.Dump.Manager", 741b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 742b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" + 743b47452b2SAsmitha Karunanithi entryID, 7445cb1dd27SAsmitha Karunanithi "xyz.openbmc_project.Object.Delete", "Delete"); 7455cb1dd27SAsmitha Karunanithi } 7465cb1dd27SAsmitha Karunanithi 747168d1b1aSCarson Labrado inline void 748168d1b1aSCarson Labrado downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 749168d1b1aSCarson Labrado const std::string& entryID, 750168d1b1aSCarson Labrado const std::string& downloadEntryType, 751168d1b1aSCarson Labrado const boost::system::error_code& ec, 752168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) 753168d1b1aSCarson Labrado { 754168d1b1aSCarson Labrado if (ec.value() == EBADR) 755168d1b1aSCarson Labrado { 756168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 757168d1b1aSCarson Labrado return; 758168d1b1aSCarson Labrado } 759168d1b1aSCarson Labrado if (ec) 760168d1b1aSCarson Labrado { 761168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 762168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 763168d1b1aSCarson Labrado return; 764168d1b1aSCarson Labrado } 765168d1b1aSCarson Labrado 766168d1b1aSCarson Labrado // Make sure we know how to process the retrieved entry attachment 767168d1b1aSCarson Labrado if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 768168d1b1aSCarson Labrado { 769168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 770168d1b1aSCarson Labrado downloadEntryType); 771168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 772168d1b1aSCarson Labrado } 773168d1b1aSCarson Labrado 774168d1b1aSCarson Labrado int fd = -1; 775168d1b1aSCarson Labrado fd = dup(unixfd); 776168d1b1aSCarson Labrado if (fd < 0) 777168d1b1aSCarson Labrado { 778168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to open file"); 779168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 780168d1b1aSCarson Labrado return; 781168d1b1aSCarson Labrado } 782168d1b1aSCarson Labrado 783168d1b1aSCarson Labrado long long int size = lseek(fd, 0, SEEK_END); 784168d1b1aSCarson Labrado if (size <= 0) 785168d1b1aSCarson Labrado { 786168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 787168d1b1aSCarson Labrado size); 788168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 789168d1b1aSCarson Labrado close(fd); 790168d1b1aSCarson Labrado return; 791168d1b1aSCarson Labrado } 792168d1b1aSCarson Labrado 793168d1b1aSCarson Labrado // Arbitrary max size of 20MB to accommodate BMC dumps 794168d1b1aSCarson Labrado constexpr int maxFileSize = 20 * 1024 * 1024; 795168d1b1aSCarson Labrado if (size > maxFileSize) 796168d1b1aSCarson Labrado { 797168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 798168d1b1aSCarson Labrado size, maxFileSize); 799168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 800168d1b1aSCarson Labrado close(fd); 801168d1b1aSCarson Labrado return; 802168d1b1aSCarson Labrado } 803168d1b1aSCarson Labrado long long int rc = lseek(fd, 0, SEEK_SET); 804168d1b1aSCarson Labrado if (rc < 0) 805168d1b1aSCarson Labrado { 806168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 807168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 808168d1b1aSCarson Labrado close(fd); 809168d1b1aSCarson Labrado return; 810168d1b1aSCarson Labrado } 811168d1b1aSCarson Labrado 81227b0cf90SEd Tanous std::string body; 81327b0cf90SEd Tanous body.resize(static_cast<size_t>(size), '\0'); 81427b0cf90SEd Tanous rc = read(fd, body.data(), body.size()); 815168d1b1aSCarson Labrado if ((rc == -1) || (rc != size)) 816168d1b1aSCarson Labrado { 817168d1b1aSCarson Labrado BMCWEB_LOG_ERROR("Failed to read in file"); 818168d1b1aSCarson Labrado messages::internalError(asyncResp->res); 819168d1b1aSCarson Labrado close(fd); 820168d1b1aSCarson Labrado return; 821168d1b1aSCarson Labrado } 822168d1b1aSCarson Labrado close(fd); 823168d1b1aSCarson Labrado if (downloadEntryType == "System") 824168d1b1aSCarson Labrado { 82527b0cf90SEd Tanous // Base64 encode response. 82627b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(body)); 827168d1b1aSCarson Labrado asyncResp->res.addHeader( 828168d1b1aSCarson Labrado boost::beast::http::field::content_transfer_encoding, "Base64"); 829168d1b1aSCarson Labrado } 83027b0cf90SEd Tanous else 83127b0cf90SEd Tanous { 83227b0cf90SEd Tanous asyncResp->res.write(std::move(body)); 83327b0cf90SEd Tanous } 834168d1b1aSCarson Labrado 835168d1b1aSCarson Labrado asyncResp->res.addHeader(boost::beast::http::field::content_type, 836168d1b1aSCarson Labrado "application/octet-stream"); 837168d1b1aSCarson Labrado } 838168d1b1aSCarson Labrado 839168d1b1aSCarson Labrado inline void 840168d1b1aSCarson Labrado downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 841168d1b1aSCarson Labrado const std::string& entryID, const std::string& dumpType) 842168d1b1aSCarson Labrado { 843168d1b1aSCarson Labrado if (dumpType != "BMC") 844168d1b1aSCarson Labrado { 845168d1b1aSCarson Labrado BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID); 846168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID); 847168d1b1aSCarson Labrado return; 848168d1b1aSCarson Labrado } 849168d1b1aSCarson Labrado 850168d1b1aSCarson Labrado std::string dumpEntryPath = 851168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/dump/") / 852168d1b1aSCarson Labrado std::string(boost::algorithm::to_lower_copy(dumpType)) / "entry" / 853168d1b1aSCarson Labrado entryID; 854168d1b1aSCarson Labrado 855168d1b1aSCarson Labrado auto downloadDumpEntryHandler = 856168d1b1aSCarson Labrado [asyncResp, entryID, 857168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 858168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 859168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 860168d1b1aSCarson Labrado }; 861168d1b1aSCarson Labrado 862168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 863168d1b1aSCarson Labrado std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager", 864168d1b1aSCarson Labrado dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle"); 865168d1b1aSCarson Labrado } 866168d1b1aSCarson Labrado 867168d1b1aSCarson Labrado inline void 868168d1b1aSCarson Labrado downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 869168d1b1aSCarson Labrado const std::string& systemName, 870168d1b1aSCarson Labrado const std::string& entryID, 871168d1b1aSCarson Labrado const std::string& dumpType) 872168d1b1aSCarson Labrado { 873168d1b1aSCarson Labrado if constexpr (bmcwebEnableMultiHost) 874168d1b1aSCarson Labrado { 875168d1b1aSCarson Labrado // Option currently returns no systems. TBD 876168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 877168d1b1aSCarson Labrado systemName); 878168d1b1aSCarson Labrado return; 879168d1b1aSCarson Labrado } 880168d1b1aSCarson Labrado if (systemName != "system") 881168d1b1aSCarson Labrado { 882168d1b1aSCarson Labrado messages::resourceNotFound(asyncResp->res, "ComputerSystem", 883168d1b1aSCarson Labrado systemName); 884168d1b1aSCarson Labrado return; 885168d1b1aSCarson Labrado } 886168d1b1aSCarson Labrado 887168d1b1aSCarson Labrado std::string entryPath = 888168d1b1aSCarson Labrado sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") / 889168d1b1aSCarson Labrado entryID; 890168d1b1aSCarson Labrado 891168d1b1aSCarson Labrado auto downloadEventLogEntryHandler = 892168d1b1aSCarson Labrado [asyncResp, entryID, 893168d1b1aSCarson Labrado dumpType](const boost::system::error_code& ec, 894168d1b1aSCarson Labrado const sdbusplus::message::unix_fd& unixfd) { 895168d1b1aSCarson Labrado downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd); 896168d1b1aSCarson Labrado }; 897168d1b1aSCarson Labrado 898168d1b1aSCarson Labrado crow::connections::systemBus->async_method_call( 899168d1b1aSCarson Labrado std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging", 900168d1b1aSCarson Labrado entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry"); 901168d1b1aSCarson Labrado } 902168d1b1aSCarson Labrado 9038e31778eSAsmitha Karunanithi inline DumpCreationProgress 9048e31778eSAsmitha Karunanithi mapDbusStatusToDumpProgress(const std::string& status) 905a43be80fSAsmitha Karunanithi { 9068e31778eSAsmitha Karunanithi if (status == 9078e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" || 9088e31778eSAsmitha Karunanithi status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted") 9098e31778eSAsmitha Karunanithi { 9108e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9118e31778eSAsmitha Karunanithi } 9128e31778eSAsmitha Karunanithi if (status == 9138e31778eSAsmitha Karunanithi "xyz.openbmc_project.Common.Progress.OperationStatus.Completed") 9148e31778eSAsmitha Karunanithi { 9158e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_SUCCESS; 9168e31778eSAsmitha Karunanithi } 9178e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9188e31778eSAsmitha Karunanithi } 9198e31778eSAsmitha Karunanithi 9208e31778eSAsmitha Karunanithi inline DumpCreationProgress 9218e31778eSAsmitha Karunanithi getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values) 9228e31778eSAsmitha Karunanithi { 9238e31778eSAsmitha Karunanithi for (const auto& [key, val] : values) 9248e31778eSAsmitha Karunanithi { 9258e31778eSAsmitha Karunanithi if (key == "Status") 9268e31778eSAsmitha Karunanithi { 9278e31778eSAsmitha Karunanithi const std::string* value = std::get_if<std::string>(&val); 9288e31778eSAsmitha Karunanithi if (value == nullptr) 9298e31778eSAsmitha Karunanithi { 93062598e31SEd Tanous BMCWEB_LOG_ERROR("Status property value is null"); 9318e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_FAILED; 9328e31778eSAsmitha Karunanithi } 9338e31778eSAsmitha Karunanithi return mapDbusStatusToDumpProgress(*value); 9348e31778eSAsmitha Karunanithi } 9358e31778eSAsmitha Karunanithi } 9368e31778eSAsmitha Karunanithi return DumpCreationProgress::DUMP_CREATE_INPROGRESS; 9378e31778eSAsmitha Karunanithi } 9388e31778eSAsmitha Karunanithi 9398e31778eSAsmitha Karunanithi inline std::string getDumpEntryPath(const std::string& dumpPath) 9408e31778eSAsmitha Karunanithi { 9418e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry") 9428e31778eSAsmitha Karunanithi { 9438e31778eSAsmitha Karunanithi return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/"; 9448e31778eSAsmitha Karunanithi } 9458e31778eSAsmitha Karunanithi if (dumpPath == "/xyz/openbmc_project/dump/system/entry") 9468e31778eSAsmitha Karunanithi { 9478e31778eSAsmitha Karunanithi return "/redfish/v1/Systems/system/LogServices/Dump/Entries/"; 9488e31778eSAsmitha Karunanithi } 9498e31778eSAsmitha Karunanithi return ""; 9508e31778eSAsmitha Karunanithi } 9518e31778eSAsmitha Karunanithi 9528e31778eSAsmitha Karunanithi inline void createDumpTaskCallback( 9538e31778eSAsmitha Karunanithi task::Payload&& payload, 9548e31778eSAsmitha Karunanithi const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9558e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& createdObjPath) 9568e31778eSAsmitha Karunanithi { 9578e31778eSAsmitha Karunanithi const std::string dumpPath = createdObjPath.parent_path().str; 9588e31778eSAsmitha Karunanithi const std::string dumpId = createdObjPath.filename(); 9598e31778eSAsmitha Karunanithi 9608e31778eSAsmitha Karunanithi std::string dumpEntryPath = getDumpEntryPath(dumpPath); 9618e31778eSAsmitha Karunanithi 9628e31778eSAsmitha Karunanithi if (dumpEntryPath.empty()) 9638e31778eSAsmitha Karunanithi { 96462598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid dump type received"); 9658e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9668e31778eSAsmitha Karunanithi return; 9678e31778eSAsmitha Karunanithi } 9688e31778eSAsmitha Karunanithi 9698e31778eSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 9708e31778eSAsmitha Karunanithi [asyncResp, payload, createdObjPath, 9718e31778eSAsmitha Karunanithi dumpEntryPath{std::move(dumpEntryPath)}, 9725e7e2dc5SEd Tanous dumpId](const boost::system::error_code& ec, 9738e31778eSAsmitha Karunanithi const std::string& introspectXml) { 9748e31778eSAsmitha Karunanithi if (ec) 9758e31778eSAsmitha Karunanithi { 97662598e31SEd Tanous BMCWEB_LOG_ERROR("Introspect call failed with error: {}", 97762598e31SEd Tanous ec.message()); 9788e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9798e31778eSAsmitha Karunanithi return; 9808e31778eSAsmitha Karunanithi } 9818e31778eSAsmitha Karunanithi 9828e31778eSAsmitha Karunanithi // Check if the created dump object has implemented Progress 9838e31778eSAsmitha Karunanithi // interface to track dump completion. If yes, fetch the "Status" 9848e31778eSAsmitha Karunanithi // property of the interface, modify the task state accordingly. 9858e31778eSAsmitha Karunanithi // Else, return task completed. 9868e31778eSAsmitha Karunanithi tinyxml2::XMLDocument doc; 9878e31778eSAsmitha Karunanithi 9888e31778eSAsmitha Karunanithi doc.Parse(introspectXml.data(), introspectXml.size()); 9898e31778eSAsmitha Karunanithi tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node"); 9908e31778eSAsmitha Karunanithi if (pRoot == nullptr) 9918e31778eSAsmitha Karunanithi { 99262598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse"); 9938e31778eSAsmitha Karunanithi messages::internalError(asyncResp->res); 9948e31778eSAsmitha Karunanithi return; 9958e31778eSAsmitha Karunanithi } 9968e31778eSAsmitha Karunanithi tinyxml2::XMLElement* interfaceNode = 9978e31778eSAsmitha Karunanithi pRoot->FirstChildElement("interface"); 9988e31778eSAsmitha Karunanithi 9998e31778eSAsmitha Karunanithi bool isProgressIntfPresent = false; 10008e31778eSAsmitha Karunanithi while (interfaceNode != nullptr) 10018e31778eSAsmitha Karunanithi { 10028e31778eSAsmitha Karunanithi const char* thisInterfaceName = interfaceNode->Attribute("name"); 10038e31778eSAsmitha Karunanithi if (thisInterfaceName != nullptr) 10048e31778eSAsmitha Karunanithi { 10058e31778eSAsmitha Karunanithi if (thisInterfaceName == 10068e31778eSAsmitha Karunanithi std::string_view("xyz.openbmc_project.Common.Progress")) 10078e31778eSAsmitha Karunanithi { 10088e31778eSAsmitha Karunanithi interfaceNode = 10098e31778eSAsmitha Karunanithi interfaceNode->NextSiblingElement("interface"); 10108e31778eSAsmitha Karunanithi continue; 10118e31778eSAsmitha Karunanithi } 10128e31778eSAsmitha Karunanithi isProgressIntfPresent = true; 10138e31778eSAsmitha Karunanithi break; 10148e31778eSAsmitha Karunanithi } 10158e31778eSAsmitha Karunanithi interfaceNode = interfaceNode->NextSiblingElement("interface"); 10168e31778eSAsmitha Karunanithi } 10178e31778eSAsmitha Karunanithi 1018a43be80fSAsmitha Karunanithi std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 10198e31778eSAsmitha Karunanithi [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent]( 10208b24275dSEd Tanous const boost::system::error_code& ec2, sdbusplus::message_t& msg, 1021a43be80fSAsmitha Karunanithi const std::shared_ptr<task::TaskData>& taskData) { 10228b24275dSEd Tanous if (ec2) 1023cb13a392SEd Tanous { 102462598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 102562598e31SEd Tanous createdObjPath.str); 10268e31778eSAsmitha Karunanithi taskData->messages.emplace_back(messages::internalError()); 10276145ed6fSAsmitha Karunanithi taskData->state = "Cancelled"; 10286145ed6fSAsmitha Karunanithi return task::completed; 1029cb13a392SEd Tanous } 1030b9d36b47SEd Tanous 10318e31778eSAsmitha Karunanithi if (isProgressIntfPresent) 1032a43be80fSAsmitha Karunanithi { 10338e31778eSAsmitha Karunanithi dbus::utility::DBusPropertiesMap values; 10348e31778eSAsmitha Karunanithi std::string prop; 10358e31778eSAsmitha Karunanithi msg.read(prop, values); 10368e31778eSAsmitha Karunanithi 10378e31778eSAsmitha Karunanithi DumpCreationProgress dumpStatus = 10388e31778eSAsmitha Karunanithi getDumpCompletionStatus(values); 10398e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED) 10408e31778eSAsmitha Karunanithi { 104162598e31SEd Tanous BMCWEB_LOG_ERROR("{}: Error in creating dump", 104262598e31SEd Tanous createdObjPath.str); 10438e31778eSAsmitha Karunanithi taskData->state = "Cancelled"; 10448e31778eSAsmitha Karunanithi return task::completed; 10458e31778eSAsmitha Karunanithi } 10468e31778eSAsmitha Karunanithi 10478e31778eSAsmitha Karunanithi if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS) 10488e31778eSAsmitha Karunanithi { 104962598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress", 105062598e31SEd Tanous createdObjPath.str); 10518e31778eSAsmitha Karunanithi return !task::completed; 10528e31778eSAsmitha Karunanithi } 10538e31778eSAsmitha Karunanithi } 10548e31778eSAsmitha Karunanithi 1055a43be80fSAsmitha Karunanithi nlohmann::json retMessage = messages::success(); 1056a43be80fSAsmitha Karunanithi taskData->messages.emplace_back(retMessage); 1057a43be80fSAsmitha Karunanithi 1058c51a58eeSEd Tanous boost::urls::url url = boost::urls::format( 1059c51a58eeSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId); 1060c51a58eeSEd Tanous 1061c51a58eeSEd Tanous std::string headerLoc = "Location: "; 1062c51a58eeSEd Tanous headerLoc += url.buffer(); 1063c51a58eeSEd Tanous 1064002d39b4SEd Tanous taskData->payload->httpHeaders.emplace_back(std::move(headerLoc)); 1065a43be80fSAsmitha Karunanithi 106662598e31SEd Tanous BMCWEB_LOG_DEBUG("{}: Dump creation task completed", 106762598e31SEd Tanous createdObjPath.str); 1068a43be80fSAsmitha Karunanithi taskData->state = "Completed"; 1069b47452b2SAsmitha Karunanithi return task::completed; 1070a43be80fSAsmitha Karunanithi }, 10718e31778eSAsmitha Karunanithi "type='signal',interface='org.freedesktop.DBus.Properties'," 10728e31778eSAsmitha Karunanithi "member='PropertiesChanged',path='" + 10738e31778eSAsmitha Karunanithi createdObjPath.str + "'"); 1074a43be80fSAsmitha Karunanithi 10758e31778eSAsmitha Karunanithi // The task timer is set to max time limit within which the 10768e31778eSAsmitha Karunanithi // requested dump will be collected. 10778e31778eSAsmitha Karunanithi task->startTimer(std::chrono::minutes(6)); 1078a43be80fSAsmitha Karunanithi task->populateResp(asyncResp->res); 10798e31778eSAsmitha Karunanithi task->payload.emplace(payload); 10808e31778eSAsmitha Karunanithi }, 10818e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", createdObjPath, 10828e31778eSAsmitha Karunanithi "org.freedesktop.DBus.Introspectable", "Introspect"); 1083a43be80fSAsmitha Karunanithi } 1084a43be80fSAsmitha Karunanithi 10858d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10868d1b46d7Szhanghch05 const crow::Request& req, const std::string& dumpType) 1087a43be80fSAsmitha Karunanithi { 1088fdd26906SClaire Weinan std::string dumpPath = getDumpEntriesPath(dumpType); 1089fdd26906SClaire Weinan if (dumpPath.empty()) 1090a43be80fSAsmitha Karunanithi { 1091a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1092a43be80fSAsmitha Karunanithi return; 1093a43be80fSAsmitha Karunanithi } 1094a43be80fSAsmitha Karunanithi 1095a43be80fSAsmitha Karunanithi std::optional<std::string> diagnosticDataType; 1096a43be80fSAsmitha Karunanithi std::optional<std::string> oemDiagnosticDataType; 1097a43be80fSAsmitha Karunanithi 109815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 1099a43be80fSAsmitha Karunanithi req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 1100a43be80fSAsmitha Karunanithi "OEMDiagnosticDataType", oemDiagnosticDataType)) 1101a43be80fSAsmitha Karunanithi { 1102a43be80fSAsmitha Karunanithi return; 1103a43be80fSAsmitha Karunanithi } 1104a43be80fSAsmitha Karunanithi 1105a43be80fSAsmitha Karunanithi if (dumpType == "System") 1106a43be80fSAsmitha Karunanithi { 1107a43be80fSAsmitha Karunanithi if (!oemDiagnosticDataType || !diagnosticDataType) 1108a43be80fSAsmitha Karunanithi { 110962598e31SEd Tanous BMCWEB_LOG_ERROR( 111062598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!"); 1111a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1112a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", 1113a43be80fSAsmitha Karunanithi "DiagnosticDataType & OEMDiagnosticDataType"); 1114a43be80fSAsmitha Karunanithi return; 1115a43be80fSAsmitha Karunanithi } 11163174e4dfSEd Tanous if ((*oemDiagnosticDataType != "System") || 1117a43be80fSAsmitha Karunanithi (*diagnosticDataType != "OEM")) 1118a43be80fSAsmitha Karunanithi { 111962598e31SEd Tanous BMCWEB_LOG_ERROR("Wrong parameter values passed"); 1120ace85d60SEd Tanous messages::internalError(asyncResp->res); 1121a43be80fSAsmitha Karunanithi return; 1122a43be80fSAsmitha Karunanithi } 11235907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/"; 1124a43be80fSAsmitha Karunanithi } 1125a43be80fSAsmitha Karunanithi else if (dumpType == "BMC") 1126a43be80fSAsmitha Karunanithi { 1127a43be80fSAsmitha Karunanithi if (!diagnosticDataType) 1128a43be80fSAsmitha Karunanithi { 112962598e31SEd Tanous BMCWEB_LOG_ERROR( 113062598e31SEd Tanous "CreateDump action parameter 'DiagnosticDataType' not found!"); 1131a43be80fSAsmitha Karunanithi messages::actionParameterMissing( 1132a43be80fSAsmitha Karunanithi asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType"); 1133a43be80fSAsmitha Karunanithi return; 1134a43be80fSAsmitha Karunanithi } 11353174e4dfSEd Tanous if (*diagnosticDataType != "Manager") 1136a43be80fSAsmitha Karunanithi { 113762598e31SEd Tanous BMCWEB_LOG_ERROR( 113862598e31SEd Tanous "Wrong parameter value passed for 'DiagnosticDataType'"); 1139ace85d60SEd Tanous messages::internalError(asyncResp->res); 1140a43be80fSAsmitha Karunanithi return; 1141a43be80fSAsmitha Karunanithi } 11425907571dSAsmitha Karunanithi dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/"; 11435907571dSAsmitha Karunanithi } 11445907571dSAsmitha Karunanithi else 11455907571dSAsmitha Karunanithi { 114662598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type"); 11475907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11485907571dSAsmitha Karunanithi return; 1149a43be80fSAsmitha Karunanithi } 1150a43be80fSAsmitha Karunanithi 11518e31778eSAsmitha Karunanithi std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>> 11528e31778eSAsmitha Karunanithi createDumpParamVec; 11538e31778eSAsmitha Karunanithi 1154f574a8e1SCarson Labrado if (req.session != nullptr) 1155f574a8e1SCarson Labrado { 115668dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 115768dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId", 115868dd075aSAsmitha Karunanithi req.session->clientIp); 115968dd075aSAsmitha Karunanithi createDumpParamVec.emplace_back( 116068dd075aSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType", 116168dd075aSAsmitha Karunanithi "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client"); 1162f574a8e1SCarson Labrado } 116368dd075aSAsmitha Karunanithi 1164a43be80fSAsmitha Karunanithi crow::connections::systemBus->async_method_call( 11655e7e2dc5SEd Tanous [asyncResp, payload(task::Payload(req)), 11665e7e2dc5SEd Tanous dumpPath](const boost::system::error_code& ec, 11675e7e2dc5SEd Tanous const sdbusplus::message_t& msg, 11688e31778eSAsmitha Karunanithi const sdbusplus::message::object_path& objPath) mutable { 1169a43be80fSAsmitha Karunanithi if (ec) 1170a43be80fSAsmitha Karunanithi { 117162598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec); 11725907571dSAsmitha Karunanithi const sd_bus_error* dbusError = msg.get_error(); 11735907571dSAsmitha Karunanithi if (dbusError == nullptr) 11745907571dSAsmitha Karunanithi { 11755907571dSAsmitha Karunanithi messages::internalError(asyncResp->res); 11765907571dSAsmitha Karunanithi return; 11775907571dSAsmitha Karunanithi } 11785907571dSAsmitha Karunanithi 117962598e31SEd Tanous BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}", 118062598e31SEd Tanous dbusError->name, dbusError->message); 11815907571dSAsmitha Karunanithi if (std::string_view( 11825907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.NotAllowed") == 11835907571dSAsmitha Karunanithi dbusError->name) 11845907571dSAsmitha Karunanithi { 11855907571dSAsmitha Karunanithi messages::resourceInStandby(asyncResp->res); 11865907571dSAsmitha Karunanithi return; 11875907571dSAsmitha Karunanithi } 11885907571dSAsmitha Karunanithi if (std::string_view( 11895907571dSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create.Error.Disabled") == 11905907571dSAsmitha Karunanithi dbusError->name) 11915907571dSAsmitha Karunanithi { 11925907571dSAsmitha Karunanithi messages::serviceDisabled(asyncResp->res, dumpPath); 11935907571dSAsmitha Karunanithi return; 11945907571dSAsmitha Karunanithi } 11955907571dSAsmitha Karunanithi if (std::string_view( 11965907571dSAsmitha Karunanithi "xyz.openbmc_project.Common.Error.Unavailable") == 11975907571dSAsmitha Karunanithi dbusError->name) 11985907571dSAsmitha Karunanithi { 11995907571dSAsmitha Karunanithi messages::resourceInUse(asyncResp->res); 12005907571dSAsmitha Karunanithi return; 12015907571dSAsmitha Karunanithi } 12025907571dSAsmitha Karunanithi // Other Dbus errors such as: 12035907571dSAsmitha Karunanithi // xyz.openbmc_project.Common.Error.InvalidArgument & 12045907571dSAsmitha Karunanithi // org.freedesktop.DBus.Error.InvalidArgs are all related to 12055907571dSAsmitha Karunanithi // the dbus call that is made here in the bmcweb 12065907571dSAsmitha Karunanithi // implementation and has nothing to do with the client's 12075907571dSAsmitha Karunanithi // input in the request. Hence, returning internal error 12085907571dSAsmitha Karunanithi // back to the client. 1209a43be80fSAsmitha Karunanithi messages::internalError(asyncResp->res); 1210a43be80fSAsmitha Karunanithi return; 1211a43be80fSAsmitha Karunanithi } 121262598e31SEd Tanous BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str); 12138e31778eSAsmitha Karunanithi createDumpTaskCallback(std::move(payload), asyncResp, objPath); 1214a43be80fSAsmitha Karunanithi }, 1215b47452b2SAsmitha Karunanithi "xyz.openbmc_project.Dump.Manager", 1216b47452b2SAsmitha Karunanithi "/xyz/openbmc_project/dump/" + 1217b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)), 12188e31778eSAsmitha Karunanithi "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec); 1219a43be80fSAsmitha Karunanithi } 1220a43be80fSAsmitha Karunanithi 12218d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12228d1b46d7Szhanghch05 const std::string& dumpType) 122380319af1SAsmitha Karunanithi { 1224b47452b2SAsmitha Karunanithi std::string dumpTypeLowerCopy = 1225b47452b2SAsmitha Karunanithi std::string(boost::algorithm::to_lower_copy(dumpType)); 12268d1b46d7Szhanghch05 12270d946211SClaire Weinan crow::connections::systemBus->async_method_call( 12280d946211SClaire Weinan [asyncResp](const boost::system::error_code& ec) { 122980319af1SAsmitha Karunanithi if (ec) 123080319af1SAsmitha Karunanithi { 123162598e31SEd Tanous BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec); 123280319af1SAsmitha Karunanithi messages::internalError(asyncResp->res); 123380319af1SAsmitha Karunanithi return; 123480319af1SAsmitha Karunanithi } 12350d946211SClaire Weinan }, 12360d946211SClaire Weinan "xyz.openbmc_project.Dump.Manager", 12370d946211SClaire Weinan "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 12380d946211SClaire Weinan "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 123980319af1SAsmitha Karunanithi } 124080319af1SAsmitha Karunanithi 1241b9d36b47SEd Tanous inline static void 1242b9d36b47SEd Tanous parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params, 1243b9d36b47SEd Tanous std::string& filename, std::string& timestamp, 1244b9d36b47SEd Tanous std::string& logfile) 1245043a0536SJohnathan Mantey { 1246d1bde9e5SKrzysztof Grobelny const std::string* filenamePtr = nullptr; 1247d1bde9e5SKrzysztof Grobelny const std::string* timestampPtr = nullptr; 1248d1bde9e5SKrzysztof Grobelny const std::string* logfilePtr = nullptr; 1249d1bde9e5SKrzysztof Grobelny 1250d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1251d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr, 1252d1bde9e5SKrzysztof Grobelny "Filename", filenamePtr, "Log", logfilePtr); 1253d1bde9e5SKrzysztof Grobelny 1254d1bde9e5SKrzysztof Grobelny if (!success) 1255043a0536SJohnathan Mantey { 1256d1bde9e5SKrzysztof Grobelny return; 1257043a0536SJohnathan Mantey } 1258d1bde9e5SKrzysztof Grobelny 1259d1bde9e5SKrzysztof Grobelny if (filenamePtr != nullptr) 1260043a0536SJohnathan Mantey { 1261d1bde9e5SKrzysztof Grobelny filename = *filenamePtr; 1262d1bde9e5SKrzysztof Grobelny } 1263d1bde9e5SKrzysztof Grobelny 1264d1bde9e5SKrzysztof Grobelny if (timestampPtr != nullptr) 1265043a0536SJohnathan Mantey { 1266d1bde9e5SKrzysztof Grobelny timestamp = *timestampPtr; 1267043a0536SJohnathan Mantey } 1268d1bde9e5SKrzysztof Grobelny 1269d1bde9e5SKrzysztof Grobelny if (logfilePtr != nullptr) 1270043a0536SJohnathan Mantey { 1271d1bde9e5SKrzysztof Grobelny logfile = *logfilePtr; 1272043a0536SJohnathan Mantey } 1273043a0536SJohnathan Mantey } 1274043a0536SJohnathan Mantey 12757e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app) 12761da66f75SEd Tanous { 1277c4bf6374SJason M. Bills /** 1278c4bf6374SJason M. Bills * Functions triggers appropriate requests on DBus 1279c4bf6374SJason M. Bills */ 128022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/") 1281ed398213SEd Tanous .privileges(redfish::privileges::getLogServiceCollection) 1282002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1283002d39b4SEd Tanous [&app](const crow::Request& req, 128422d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 128522d268cbSEd Tanous const std::string& systemName) { 12863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1287c4bf6374SJason M. Bills { 128845ca1b86SEd Tanous return; 128945ca1b86SEd Tanous } 12907f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 12917f3e84a1SEd Tanous { 12927f3e84a1SEd Tanous // Option currently returns no systems. TBD 12937f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 12947f3e84a1SEd Tanous systemName); 12957f3e84a1SEd Tanous return; 12967f3e84a1SEd Tanous } 129722d268cbSEd Tanous if (systemName != "system") 129822d268cbSEd Tanous { 129922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 130022d268cbSEd Tanous systemName); 130122d268cbSEd Tanous return; 130222d268cbSEd Tanous } 130322d268cbSEd Tanous 13047e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 13057e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1306c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1307c4bf6374SJason M. Bills "#LogServiceCollection.LogServiceCollection"; 1308c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1309029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices"; 131045ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Log Services Collection"; 1311c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1312c4bf6374SJason M. Bills "Collection of LogServices for this Computer System"; 1313002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 1314c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 13151476687dSEd Tanous nlohmann::json::object_t eventLog; 13161476687dSEd Tanous eventLog["@odata.id"] = 13171476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1318b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(eventLog)); 13195cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 13201476687dSEd Tanous nlohmann::json::object_t dumpLog; 1321002d39b4SEd Tanous dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump"; 1322b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(dumpLog)); 1323c9bb6861Sraviteja-b #endif 1324c9bb6861Sraviteja-b 1325d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG 13261476687dSEd Tanous nlohmann::json::object_t crashdump; 13271476687dSEd Tanous crashdump["@odata.id"] = 13281476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump"; 1329b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(crashdump)); 1330d53dd41fSJason M. Bills #endif 1331b7028ebfSSpencer Ku 1332b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER 13331476687dSEd Tanous nlohmann::json::object_t hostlogger; 13341476687dSEd Tanous hostlogger["@odata.id"] = 13351476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger"; 1336b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(hostlogger)); 1337b7028ebfSSpencer Ku #endif 1338c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 1339c4bf6374SJason M. Bills logServiceArray.size(); 1340a3316fc6SZhikuiRen 13417a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 13427a1dbc48SGeorge Liu "xyz.openbmc_project.State.Boot.PostCode"}; 13437a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 13447a1dbc48SGeorge Liu "/", 0, interfaces, 13457a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 1346b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 1347b9d36b47SEd Tanous subtreePath) { 1348a3316fc6SZhikuiRen if (ec) 1349a3316fc6SZhikuiRen { 135062598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 1351a3316fc6SZhikuiRen return; 1352a3316fc6SZhikuiRen } 1353a3316fc6SZhikuiRen 135455f79e6fSEd Tanous for (const auto& pathStr : subtreePath) 1355a3316fc6SZhikuiRen { 1356a3316fc6SZhikuiRen if (pathStr.find("PostCode") != std::string::npos) 1357a3316fc6SZhikuiRen { 135823a21a1cSEd Tanous nlohmann::json& logServiceArrayLocal = 1359a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"]; 1360613dabeaSEd Tanous nlohmann::json::object_t member; 1361613dabeaSEd Tanous member["@odata.id"] = 1362613dabeaSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 1363613dabeaSEd Tanous 1364b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 1365613dabeaSEd Tanous 136645ca1b86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 136723a21a1cSEd Tanous logServiceArrayLocal.size(); 1368a3316fc6SZhikuiRen return; 1369a3316fc6SZhikuiRen } 1370a3316fc6SZhikuiRen } 13717a1dbc48SGeorge Liu }); 13727e860f15SJohn Edward Broadbent }); 1373c4bf6374SJason M. Bills } 1374c4bf6374SJason M. Bills 13757e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app) 1376c4bf6374SJason M. Bills { 137722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/") 1378ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 1379002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1380002d39b4SEd Tanous [&app](const crow::Request& req, 138122d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 138222d268cbSEd Tanous const std::string& systemName) { 13833ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 138445ca1b86SEd Tanous { 138545ca1b86SEd Tanous return; 138645ca1b86SEd Tanous } 138722d268cbSEd Tanous if (systemName != "system") 138822d268cbSEd Tanous { 138922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 139022d268cbSEd Tanous systemName); 139122d268cbSEd Tanous return; 139222d268cbSEd Tanous } 1393c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1394029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog"; 1395c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1396b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 1397c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "Event Log Service"; 1398002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "System Event Log Service"; 1399c4bf6374SJason M. Bills asyncResp->res.jsonValue["Id"] = "EventLog"; 1400c4bf6374SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 14017c8c4058STejas Patil 14027c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 14032b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 14047c8c4058STejas Patil 14057c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 14067c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 14077c8c4058STejas Patil redfishDateTimeOffset.second; 14087c8c4058STejas Patil 14091476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 14101476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1411e7d6c8b2SGunnar Mills asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 1412e7d6c8b2SGunnar Mills 14130fda0f12SGeorge Liu {"target", 14140fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}}; 14157e860f15SJohn Edward Broadbent }); 1416489640c6SJason M. Bills } 1417489640c6SJason M. Bills 14187e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app) 1419489640c6SJason M. Bills { 14204978b63fSJason M. Bills BMCWEB_ROUTE( 14214978b63fSJason M. Bills app, 142222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 1423432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 14247e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 142545ca1b86SEd Tanous [&app](const crow::Request& req, 142622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 142722d268cbSEd Tanous const std::string& systemName) { 14283ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 142945ca1b86SEd Tanous { 143045ca1b86SEd Tanous return; 143145ca1b86SEd Tanous } 143222d268cbSEd Tanous if (systemName != "system") 143322d268cbSEd Tanous { 143422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 143522d268cbSEd Tanous systemName); 143622d268cbSEd Tanous return; 143722d268cbSEd Tanous } 1438489640c6SJason M. Bills // Clear the EventLog by deleting the log files 1439489640c6SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1440489640c6SJason M. Bills if (getRedfishLogFiles(redfishLogFiles)) 1441489640c6SJason M. Bills { 1442489640c6SJason M. Bills for (const std::filesystem::path& file : redfishLogFiles) 1443489640c6SJason M. Bills { 1444489640c6SJason M. Bills std::error_code ec; 1445489640c6SJason M. Bills std::filesystem::remove(file, ec); 1446489640c6SJason M. Bills } 1447489640c6SJason M. Bills } 1448489640c6SJason M. Bills 1449489640c6SJason M. Bills // Reload rsyslog so it knows to start new log files 1450489640c6SJason M. Bills crow::connections::systemBus->async_method_call( 14515e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 1452489640c6SJason M. Bills if (ec) 1453489640c6SJason M. Bills { 145462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec); 1455489640c6SJason M. Bills messages::internalError(asyncResp->res); 1456489640c6SJason M. Bills return; 1457489640c6SJason M. Bills } 1458489640c6SJason M. Bills 1459489640c6SJason M. Bills messages::success(asyncResp->res); 1460489640c6SJason M. Bills }, 1461489640c6SJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 1462002d39b4SEd Tanous "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service", 1463002d39b4SEd Tanous "replace"); 14647e860f15SJohn Edward Broadbent }); 1465c4bf6374SJason M. Bills } 1466c4bf6374SJason M. Bills 1467ac992cdeSJason M. Bills enum class LogParseError 1468ac992cdeSJason M. Bills { 1469ac992cdeSJason M. Bills success, 1470ac992cdeSJason M. Bills parseFailed, 1471ac992cdeSJason M. Bills messageIdNotInRegistry, 1472ac992cdeSJason M. Bills }; 1473ac992cdeSJason M. Bills 1474ac992cdeSJason M. Bills static LogParseError 1475ac992cdeSJason M. Bills fillEventLogEntryJson(const std::string& logEntryID, 1476b5a76932SEd Tanous const std::string& logEntry, 1477de703c5dSJason M. Bills nlohmann::json::object_t& logEntryJson) 1478c4bf6374SJason M. Bills { 147995820184SJason M. Bills // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>" 1480cd225da8SJason M. Bills // First get the Timestamp 1481f23b7296SEd Tanous size_t space = logEntry.find_first_of(' '); 1482cd225da8SJason M. Bills if (space == std::string::npos) 148395820184SJason M. Bills { 1484ac992cdeSJason M. Bills return LogParseError::parseFailed; 148595820184SJason M. Bills } 1486cd225da8SJason M. Bills std::string timestamp = logEntry.substr(0, space); 1487cd225da8SJason M. Bills // Then get the log contents 1488f23b7296SEd Tanous size_t entryStart = logEntry.find_first_not_of(' ', space); 1489cd225da8SJason M. Bills if (entryStart == std::string::npos) 1490cd225da8SJason M. Bills { 1491ac992cdeSJason M. Bills return LogParseError::parseFailed; 1492cd225da8SJason M. Bills } 1493cd225da8SJason M. Bills std::string_view entry(logEntry); 1494cd225da8SJason M. Bills entry.remove_prefix(entryStart); 1495cd225da8SJason M. Bills // Use split to separate the entry into its fields 1496cd225da8SJason M. Bills std::vector<std::string> logEntryFields; 149750ebd4afSEd Tanous bmcweb::split(logEntryFields, entry, ','); 1498cd225da8SJason M. Bills // We need at least a MessageId to be valid 14991e6deaf6SEd Tanous auto logEntryIter = logEntryFields.begin(); 15001e6deaf6SEd Tanous if (logEntryIter == logEntryFields.end()) 1501cd225da8SJason M. Bills { 1502ac992cdeSJason M. Bills return LogParseError::parseFailed; 1503cd225da8SJason M. Bills } 15041e6deaf6SEd Tanous std::string& messageID = *logEntryIter; 15054851d45dSJason M. Bills // Get the Message from the MessageRegistry 1506fffb8c1fSEd Tanous const registries::Message* message = registries::getMessage(messageID); 1507c4bf6374SJason M. Bills 15081e6deaf6SEd Tanous logEntryIter++; 150954417b02SSui Chen if (message == nullptr) 1510c4bf6374SJason M. Bills { 151162598e31SEd Tanous BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry); 1512ac992cdeSJason M. Bills return LogParseError::messageIdNotInRegistry; 1513c4bf6374SJason M. Bills } 1514c4bf6374SJason M. Bills 15151e6deaf6SEd Tanous std::vector<std::string_view> messageArgs(logEntryIter, 15161e6deaf6SEd Tanous logEntryFields.end()); 1517c05bba45SEd Tanous messageArgs.resize(message->numberOfArgs); 1518c05bba45SEd Tanous 15191e6deaf6SEd Tanous std::string msg = redfish::registries::fillMessageArgs(messageArgs, 15201e6deaf6SEd Tanous message->message); 15211e6deaf6SEd Tanous if (msg.empty()) 152215a86ff6SJason M. Bills { 15231e6deaf6SEd Tanous return LogParseError::parseFailed; 152415a86ff6SJason M. Bills } 15254851d45dSJason M. Bills 152695820184SJason M. Bills // Get the Created time from the timestamp. The log timestamp is in RFC3339 152795820184SJason M. Bills // format which matches the Redfish format except for the fractional seconds 152895820184SJason M. Bills // between the '.' and the '+', so just remove them. 1529f23b7296SEd Tanous std::size_t dot = timestamp.find_first_of('.'); 1530f23b7296SEd Tanous std::size_t plus = timestamp.find_first_of('+'); 153195820184SJason M. Bills if (dot != std::string::npos && plus != std::string::npos) 1532c4bf6374SJason M. Bills { 153395820184SJason M. Bills timestamp.erase(dot, plus - dot); 1534c4bf6374SJason M. Bills } 1535c4bf6374SJason M. Bills 1536c4bf6374SJason M. Bills // Fill in the log entry with the gathered data 15379c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1538ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 1539ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1540ef4c65b7SEd Tanous logEntryID); 154184afc48bSJason M. Bills logEntryJson["Name"] = "System Event Log Entry"; 154284afc48bSJason M. Bills logEntryJson["Id"] = logEntryID; 154384afc48bSJason M. Bills logEntryJson["Message"] = std::move(msg); 154484afc48bSJason M. Bills logEntryJson["MessageId"] = std::move(messageID); 154584afc48bSJason M. Bills logEntryJson["MessageArgs"] = messageArgs; 154684afc48bSJason M. Bills logEntryJson["EntryType"] = "Event"; 154784afc48bSJason M. Bills logEntryJson["Severity"] = message->messageSeverity; 154884afc48bSJason M. Bills logEntryJson["Created"] = std::move(timestamp); 1549ac992cdeSJason M. Bills return LogParseError::success; 1550c4bf6374SJason M. Bills } 1551c4bf6374SJason M. Bills 15527e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app) 1553c4bf6374SJason M. Bills { 155422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 15558b6a35f0SGunnar Mills .privileges(redfish::privileges::getLogEntryCollection) 1556002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1557002d39b4SEd Tanous [&app](const crow::Request& req, 155822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 155922d268cbSEd Tanous const std::string& systemName) { 1560c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 1561c937d2bfSEd Tanous .canDelegateTop = true, 1562c937d2bfSEd Tanous .canDelegateSkip = true, 1563c937d2bfSEd Tanous }; 1564c937d2bfSEd Tanous query_param::Query delegatedQuery; 1565c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 15663ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 1567c4bf6374SJason M. Bills { 1568c4bf6374SJason M. Bills return; 1569c4bf6374SJason M. Bills } 15707f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 15717f3e84a1SEd Tanous { 15727f3e84a1SEd Tanous // Option currently returns no systems. TBD 15737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 15747f3e84a1SEd Tanous systemName); 15757f3e84a1SEd Tanous return; 15767f3e84a1SEd Tanous } 157722d268cbSEd Tanous if (systemName != "system") 157822d268cbSEd Tanous { 157922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 158022d268cbSEd Tanous systemName); 158122d268cbSEd Tanous return; 158222d268cbSEd Tanous } 158322d268cbSEd Tanous 15845143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 15853648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 15863648c8beSEd Tanous 15877e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 15887e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 1589c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 1590c4bf6374SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 1591c4bf6374SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 1592029573d4SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 1593c4bf6374SJason M. Bills asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 1594c4bf6374SJason M. Bills asyncResp->res.jsonValue["Description"] = 1595c4bf6374SJason M. Bills "Collection of System Event Log Entries"; 1596cb92c03bSAndrew Geissler 15974978b63fSJason M. Bills nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 1598c4bf6374SJason M. Bills logEntryArray = nlohmann::json::array(); 15997e860f15SJohn Edward Broadbent // Go through the log files and create a unique ID for each 16007e860f15SJohn Edward Broadbent // entry 160195820184SJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 160295820184SJason M. Bills getRedfishLogFiles(redfishLogFiles); 1603b01bf299SEd Tanous uint64_t entryCount = 0; 1604cd225da8SJason M. Bills std::string logEntry; 160595820184SJason M. Bills 16067e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16077e860f15SJohn Edward Broadbent // backwards 1608002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1609002d39b4SEd Tanous it++) 1610c4bf6374SJason M. Bills { 1611cd225da8SJason M. Bills std::ifstream logStream(*it); 161295820184SJason M. Bills if (!logStream.is_open()) 1613c4bf6374SJason M. Bills { 1614c4bf6374SJason M. Bills continue; 1615c4bf6374SJason M. Bills } 1616c4bf6374SJason M. Bills 1617e85d6b16SJason M. Bills // Reset the unique ID on the first entry 1618e85d6b16SJason M. Bills bool firstEntry = true; 161995820184SJason M. Bills while (std::getline(logStream, logEntry)) 162095820184SJason M. Bills { 1621c4bf6374SJason M. Bills std::string idStr; 1622e85d6b16SJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1623c4bf6374SJason M. Bills { 1624c4bf6374SJason M. Bills continue; 1625c4bf6374SJason M. Bills } 1626e85d6b16SJason M. Bills firstEntry = false; 1627e85d6b16SJason M. Bills 1628de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 162989492a15SPatrick Williams LogParseError status = fillEventLogEntryJson(idStr, logEntry, 163089492a15SPatrick Williams bmcLogEntry); 1631ac992cdeSJason M. Bills if (status == LogParseError::messageIdNotInRegistry) 1632ac992cdeSJason M. Bills { 1633ac992cdeSJason M. Bills continue; 1634ac992cdeSJason M. Bills } 1635ac992cdeSJason M. Bills if (status != LogParseError::success) 1636c4bf6374SJason M. Bills { 1637c4bf6374SJason M. Bills messages::internalError(asyncResp->res); 1638c4bf6374SJason M. Bills return; 1639c4bf6374SJason M. Bills } 1640de703c5dSJason M. Bills 1641de703c5dSJason M. Bills entryCount++; 1642de703c5dSJason M. Bills // Handle paging using skip (number of entries to skip from the 1643de703c5dSJason M. Bills // start) and top (number of entries to display) 16443648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 1645de703c5dSJason M. Bills { 1646de703c5dSJason M. Bills continue; 1647de703c5dSJason M. Bills } 1648de703c5dSJason M. Bills 1649b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 1650c4bf6374SJason M. Bills } 165195820184SJason M. Bills } 1652c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 16533648c8beSEd Tanous if (skip + top < entryCount) 1654c4bf6374SJason M. Bills { 1655c4bf6374SJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 16564978b63fSJason M. Bills "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" + 16573648c8beSEd Tanous std::to_string(skip + top); 1658c4bf6374SJason M. Bills } 16597e860f15SJohn Edward Broadbent }); 1660897967deSJason M. Bills } 1661897967deSJason M. Bills 16627e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app) 1663897967deSJason M. Bills { 16647e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 166522d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1666ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 16677e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 166845ca1b86SEd Tanous [&app](const crow::Request& req, 16697e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 167022d268cbSEd Tanous const std::string& systemName, const std::string& param) { 16713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 167245ca1b86SEd Tanous { 167345ca1b86SEd Tanous return; 167445ca1b86SEd Tanous } 16757f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 16767f3e84a1SEd Tanous { 16777f3e84a1SEd Tanous // Option currently returns no systems. TBD 16787f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 16797f3e84a1SEd Tanous systemName); 16807f3e84a1SEd Tanous return; 16817f3e84a1SEd Tanous } 168222d268cbSEd Tanous 168322d268cbSEd Tanous if (systemName != "system") 168422d268cbSEd Tanous { 168522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 168622d268cbSEd Tanous systemName); 168722d268cbSEd Tanous return; 168822d268cbSEd Tanous } 168922d268cbSEd Tanous 16907e860f15SJohn Edward Broadbent const std::string& targetID = param; 16918d1b46d7Szhanghch05 16927e860f15SJohn Edward Broadbent // Go through the log files and check the unique ID for each 16937e860f15SJohn Edward Broadbent // entry to find the target entry 1694897967deSJason M. Bills std::vector<std::filesystem::path> redfishLogFiles; 1695897967deSJason M. Bills getRedfishLogFiles(redfishLogFiles); 1696897967deSJason M. Bills std::string logEntry; 1697897967deSJason M. Bills 16987e860f15SJohn Edward Broadbent // Oldest logs are in the last file, so start there and loop 16997e860f15SJohn Edward Broadbent // backwards 1700002d39b4SEd Tanous for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); 1701002d39b4SEd Tanous it++) 1702897967deSJason M. Bills { 1703897967deSJason M. Bills std::ifstream logStream(*it); 1704897967deSJason M. Bills if (!logStream.is_open()) 1705897967deSJason M. Bills { 1706897967deSJason M. Bills continue; 1707897967deSJason M. Bills } 1708897967deSJason M. Bills 1709897967deSJason M. Bills // Reset the unique ID on the first entry 1710897967deSJason M. Bills bool firstEntry = true; 1711897967deSJason M. Bills while (std::getline(logStream, logEntry)) 1712897967deSJason M. Bills { 1713897967deSJason M. Bills std::string idStr; 1714897967deSJason M. Bills if (!getUniqueEntryID(logEntry, idStr, firstEntry)) 1715897967deSJason M. Bills { 1716897967deSJason M. Bills continue; 1717897967deSJason M. Bills } 1718897967deSJason M. Bills firstEntry = false; 1719897967deSJason M. Bills 1720897967deSJason M. Bills if (idStr == targetID) 1721897967deSJason M. Bills { 1722de703c5dSJason M. Bills nlohmann::json::object_t bmcLogEntry; 1723ac992cdeSJason M. Bills LogParseError status = 1724ac992cdeSJason M. Bills fillEventLogEntryJson(idStr, logEntry, bmcLogEntry); 1725ac992cdeSJason M. Bills if (status != LogParseError::success) 1726897967deSJason M. Bills { 1727897967deSJason M. Bills messages::internalError(asyncResp->res); 1728897967deSJason M. Bills return; 1729897967deSJason M. Bills } 1730d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcLogEntry); 1731897967deSJason M. Bills return; 1732897967deSJason M. Bills } 1733897967deSJason M. Bills } 1734897967deSJason M. Bills } 1735897967deSJason M. Bills // Requested ID was not found 17369db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", targetID); 17377e860f15SJohn Edward Broadbent }); 173808a4e4b5SAnthony Wilson } 173908a4e4b5SAnthony Wilson 17407e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app) 174108a4e4b5SAnthony Wilson { 174222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/") 1743ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 1744002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1745002d39b4SEd Tanous [&app](const crow::Request& req, 174622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174722d268cbSEd Tanous const std::string& systemName) { 17483ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 174945ca1b86SEd Tanous { 175045ca1b86SEd Tanous return; 175145ca1b86SEd Tanous } 17527f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 17537f3e84a1SEd Tanous { 17547f3e84a1SEd Tanous // Option currently returns no systems. TBD 17557f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17567f3e84a1SEd Tanous systemName); 17577f3e84a1SEd Tanous return; 17587f3e84a1SEd Tanous } 175922d268cbSEd Tanous if (systemName != "system") 176022d268cbSEd Tanous { 176122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 176222d268cbSEd Tanous systemName); 176322d268cbSEd Tanous return; 176422d268cbSEd Tanous } 176522d268cbSEd Tanous 17667e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 17677e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 176808a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.type"] = 176908a4e4b5SAnthony Wilson "#LogEntryCollection.LogEntryCollection"; 177008a4e4b5SAnthony Wilson asyncResp->res.jsonValue["@odata.id"] = 177108a4e4b5SAnthony Wilson "/redfish/v1/Systems/system/LogServices/EventLog/Entries"; 177208a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Name"] = "System Event Log Entries"; 177308a4e4b5SAnthony Wilson asyncResp->res.jsonValue["Description"] = 177408a4e4b5SAnthony Wilson "Collection of System Event Log Entries"; 177508a4e4b5SAnthony Wilson 1776cb92c03bSAndrew Geissler // DBus implementation of EventLog/Entries 1777cb92c03bSAndrew Geissler // Make call to Logging Service to find all log entry objects 17785eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/logging"); 17795eb468daSGeorge Liu dbus::utility::getManagedObjects( 17805eb468daSGeorge Liu "xyz.openbmc_project.Logging", path, 17815e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 1782914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1783cb92c03bSAndrew Geissler if (ec) 1784cb92c03bSAndrew Geissler { 1785cb92c03bSAndrew Geissler // TODO Handle for specific error code 178662598e31SEd Tanous BMCWEB_LOG_ERROR( 178762598e31SEd Tanous "getLogEntriesIfaceData resp_handler got error {}", ec); 1788cb92c03bSAndrew Geissler messages::internalError(asyncResp->res); 1789cb92c03bSAndrew Geissler return; 1790cb92c03bSAndrew Geissler } 17913544d2a7SEd Tanous nlohmann::json::array_t entriesArray; 17929eb808c1SEd Tanous for (const auto& objectPath : resp) 1793cb92c03bSAndrew Geissler { 1794914e2d5dSEd Tanous const uint32_t* id = nullptr; 1795c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1796c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1797914e2d5dSEd Tanous const std::string* severity = nullptr; 1798914e2d5dSEd Tanous const std::string* message = nullptr; 1799914e2d5dSEd Tanous const std::string* filePath = nullptr; 18009c11a172SVijay Lobo const std::string* resolution = nullptr; 180175710de2SXiaochao Ma bool resolved = false; 18029017faf2SAbhishek Patel const std::string* notify = nullptr; 18039017faf2SAbhishek Patel 18049eb808c1SEd Tanous for (const auto& interfaceMap : objectPath.second) 1805f86bb901SAdriana Kobylak { 1806f86bb901SAdriana Kobylak if (interfaceMap.first == 1807f86bb901SAdriana Kobylak "xyz.openbmc_project.Logging.Entry") 1808f86bb901SAdriana Kobylak { 1809002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 1810cb92c03bSAndrew Geissler { 1811cb92c03bSAndrew Geissler if (propertyMap.first == "Id") 1812cb92c03bSAndrew Geissler { 1813002d39b4SEd Tanous id = std::get_if<uint32_t>(&propertyMap.second); 1814cb92c03bSAndrew Geissler } 1815cb92c03bSAndrew Geissler else if (propertyMap.first == "Timestamp") 1816cb92c03bSAndrew Geissler { 1817002d39b4SEd Tanous timestamp = 1818002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18197e860f15SJohn Edward Broadbent } 1820002d39b4SEd Tanous else if (propertyMap.first == "UpdateTimestamp") 18217e860f15SJohn Edward Broadbent { 1822002d39b4SEd Tanous updateTimestamp = 1823002d39b4SEd Tanous std::get_if<uint64_t>(&propertyMap.second); 18247e860f15SJohn Edward Broadbent } 18257e860f15SJohn Edward Broadbent else if (propertyMap.first == "Severity") 18267e860f15SJohn Edward Broadbent { 18277e860f15SJohn Edward Broadbent severity = std::get_if<std::string>( 18287e860f15SJohn Edward Broadbent &propertyMap.second); 18297e860f15SJohn Edward Broadbent } 18309c11a172SVijay Lobo else if (propertyMap.first == "Resolution") 18319c11a172SVijay Lobo { 18329c11a172SVijay Lobo resolution = std::get_if<std::string>( 18339c11a172SVijay Lobo &propertyMap.second); 18349c11a172SVijay Lobo } 18357e860f15SJohn Edward Broadbent else if (propertyMap.first == "Message") 18367e860f15SJohn Edward Broadbent { 18377e860f15SJohn Edward Broadbent message = std::get_if<std::string>( 18387e860f15SJohn Edward Broadbent &propertyMap.second); 18397e860f15SJohn Edward Broadbent } 18407e860f15SJohn Edward Broadbent else if (propertyMap.first == "Resolved") 18417e860f15SJohn Edward Broadbent { 1842914e2d5dSEd Tanous const bool* resolveptr = 1843002d39b4SEd Tanous std::get_if<bool>(&propertyMap.second); 18447e860f15SJohn Edward Broadbent if (resolveptr == nullptr) 18457e860f15SJohn Edward Broadbent { 1846002d39b4SEd Tanous messages::internalError(asyncResp->res); 18477e860f15SJohn Edward Broadbent return; 18487e860f15SJohn Edward Broadbent } 18497e860f15SJohn Edward Broadbent resolved = *resolveptr; 18507e860f15SJohn Edward Broadbent } 18519017faf2SAbhishek Patel else if (propertyMap.first == 18529017faf2SAbhishek Patel "ServiceProviderNotify") 18539017faf2SAbhishek Patel { 18549017faf2SAbhishek Patel notify = std::get_if<std::string>( 18559017faf2SAbhishek Patel &propertyMap.second); 18569017faf2SAbhishek Patel if (notify == nullptr) 18579017faf2SAbhishek Patel { 18589017faf2SAbhishek Patel messages::internalError(asyncResp->res); 18599017faf2SAbhishek Patel return; 18609017faf2SAbhishek Patel } 18619017faf2SAbhishek Patel } 18627e860f15SJohn Edward Broadbent } 18637e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 18647e860f15SJohn Edward Broadbent severity == nullptr) 18657e860f15SJohn Edward Broadbent { 18667e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 18677e860f15SJohn Edward Broadbent return; 18687e860f15SJohn Edward Broadbent } 18697e860f15SJohn Edward Broadbent } 18707e860f15SJohn Edward Broadbent else if (interfaceMap.first == 18717e860f15SJohn Edward Broadbent "xyz.openbmc_project.Common.FilePath") 18727e860f15SJohn Edward Broadbent { 1873002d39b4SEd Tanous for (const auto& propertyMap : interfaceMap.second) 18747e860f15SJohn Edward Broadbent { 18757e860f15SJohn Edward Broadbent if (propertyMap.first == "Path") 18767e860f15SJohn Edward Broadbent { 18777e860f15SJohn Edward Broadbent filePath = std::get_if<std::string>( 18787e860f15SJohn Edward Broadbent &propertyMap.second); 18797e860f15SJohn Edward Broadbent } 18807e860f15SJohn Edward Broadbent } 18817e860f15SJohn Edward Broadbent } 18827e860f15SJohn Edward Broadbent } 18837e860f15SJohn Edward Broadbent // Object path without the 18847e860f15SJohn Edward Broadbent // xyz.openbmc_project.Logging.Entry interface, ignore 18857e860f15SJohn Edward Broadbent // and continue. 18867e860f15SJohn Edward Broadbent if (id == nullptr || message == nullptr || 1887c419c759SEd Tanous severity == nullptr || timestamp == nullptr || 1888c419c759SEd Tanous updateTimestamp == nullptr) 18897e860f15SJohn Edward Broadbent { 18907e860f15SJohn Edward Broadbent continue; 18917e860f15SJohn Edward Broadbent } 18923544d2a7SEd Tanous nlohmann::json& thisEntry = entriesArray.emplace_back(); 18939c11a172SVijay Lobo thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 1894ef4c65b7SEd Tanous thisEntry["@odata.id"] = boost::urls::format( 1895ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 1896ef4c65b7SEd Tanous std::to_string(*id)); 18977e860f15SJohn Edward Broadbent thisEntry["Name"] = "System Event Log Entry"; 18987e860f15SJohn Edward Broadbent thisEntry["Id"] = std::to_string(*id); 18997e860f15SJohn Edward Broadbent thisEntry["Message"] = *message; 19007e860f15SJohn Edward Broadbent thisEntry["Resolved"] = resolved; 19019c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 19029c11a172SVijay Lobo { 19039c11a172SVijay Lobo thisEntry["Resolution"] = *resolution; 19049c11a172SVijay Lobo } 19059017faf2SAbhishek Patel std::optional<bool> notifyAction = 19069017faf2SAbhishek Patel getProviderNotifyAction(*notify); 19079017faf2SAbhishek Patel if (notifyAction) 19089017faf2SAbhishek Patel { 19099017faf2SAbhishek Patel thisEntry["ServiceProviderNotified"] = *notifyAction; 19109017faf2SAbhishek Patel } 19117e860f15SJohn Edward Broadbent thisEntry["EntryType"] = "Event"; 19127e860f15SJohn Edward Broadbent thisEntry["Severity"] = 19137e860f15SJohn Edward Broadbent translateSeverityDbusToRedfish(*severity); 19147e860f15SJohn Edward Broadbent thisEntry["Created"] = 19152b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 19167e860f15SJohn Edward Broadbent thisEntry["Modified"] = 19172b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 19187e860f15SJohn Edward Broadbent if (filePath != nullptr) 19197e860f15SJohn Edward Broadbent { 19207e860f15SJohn Edward Broadbent thisEntry["AdditionalDataURI"] = 19210fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 19227e860f15SJohn Edward Broadbent std::to_string(*id) + "/attachment"; 19237e860f15SJohn Edward Broadbent } 19247e860f15SJohn Edward Broadbent } 19253544d2a7SEd Tanous std::ranges::sort(entriesArray, [](const nlohmann::json& left, 19263544d2a7SEd Tanous const nlohmann::json& right) { 19277e860f15SJohn Edward Broadbent return (left["Id"] <= right["Id"]); 19287e860f15SJohn Edward Broadbent }); 19297e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 19307e860f15SJohn Edward Broadbent entriesArray.size(); 19313544d2a7SEd Tanous asyncResp->res.jsonValue["Members"] = std::move(entriesArray); 19325eb468daSGeorge Liu }); 19337e860f15SJohn Edward Broadbent }); 19347e860f15SJohn Edward Broadbent } 19357e860f15SJohn Edward Broadbent 19367e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app) 19377e860f15SJohn Edward Broadbent { 19387e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 193922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 1940ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 1941002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1942002d39b4SEd Tanous [&app](const crow::Request& req, 19437e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 194422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 19453ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19467e860f15SJohn Edward Broadbent { 194745ca1b86SEd Tanous return; 194845ca1b86SEd Tanous } 19497f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 19507f3e84a1SEd Tanous { 19517f3e84a1SEd Tanous // Option currently returns no systems. TBD 19527f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 19537f3e84a1SEd Tanous systemName); 19547f3e84a1SEd Tanous return; 19557f3e84a1SEd Tanous } 195622d268cbSEd Tanous if (systemName != "system") 195722d268cbSEd Tanous { 195822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 195922d268cbSEd Tanous systemName); 196022d268cbSEd Tanous return; 196122d268cbSEd Tanous } 196222d268cbSEd Tanous 19637e860f15SJohn Edward Broadbent std::string entryID = param; 19647e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(entryID); 19657e860f15SJohn Edward Broadbent 19667e860f15SJohn Edward Broadbent // DBus implementation of EventLog/Entries 19677e860f15SJohn Edward Broadbent // Make call to Logging Service to find all log entry objects 1968d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1969d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.Logging", 1970d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/logging/entry/" + entryID, "", 19715e7e2dc5SEd Tanous [asyncResp, entryID](const boost::system::error_code& ec, 1972b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 19737e860f15SJohn Edward Broadbent if (ec.value() == EBADR) 19747e860f15SJohn Edward Broadbent { 1975d1bde9e5SKrzysztof Grobelny messages::resourceNotFound(asyncResp->res, "EventLogEntry", 1976d1bde9e5SKrzysztof Grobelny entryID); 19777e860f15SJohn Edward Broadbent return; 19787e860f15SJohn Edward Broadbent } 19797e860f15SJohn Edward Broadbent if (ec) 19807e860f15SJohn Edward Broadbent { 198162598e31SEd Tanous BMCWEB_LOG_ERROR( 198262598e31SEd Tanous "EventLogEntry (DBus) resp_handler got error {}", ec); 19837e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 19847e860f15SJohn Edward Broadbent return; 19857e860f15SJohn Edward Broadbent } 1986914e2d5dSEd Tanous const uint32_t* id = nullptr; 1987c419c759SEd Tanous const uint64_t* timestamp = nullptr; 1988c419c759SEd Tanous const uint64_t* updateTimestamp = nullptr; 1989914e2d5dSEd Tanous const std::string* severity = nullptr; 1990914e2d5dSEd Tanous const std::string* message = nullptr; 1991914e2d5dSEd Tanous const std::string* filePath = nullptr; 19929c11a172SVijay Lobo const std::string* resolution = nullptr; 19937e860f15SJohn Edward Broadbent bool resolved = false; 19949017faf2SAbhishek Patel const std::string* notify = nullptr; 19957e860f15SJohn Edward Broadbent 1996d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1997d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp", 1998d1bde9e5SKrzysztof Grobelny timestamp, "UpdateTimestamp", updateTimestamp, "Severity", 19999c11a172SVijay Lobo severity, "Message", message, "Resolved", resolved, 20009017faf2SAbhishek Patel "Resolution", resolution, "Path", filePath, 20019017faf2SAbhishek Patel "ServiceProviderNotify", notify); 2002d1bde9e5SKrzysztof Grobelny 2003d1bde9e5SKrzysztof Grobelny if (!success) 200475710de2SXiaochao Ma { 200575710de2SXiaochao Ma messages::internalError(asyncResp->res); 200675710de2SXiaochao Ma return; 200775710de2SXiaochao Ma } 2008d1bde9e5SKrzysztof Grobelny 2009002d39b4SEd Tanous if (id == nullptr || message == nullptr || severity == nullptr || 20109017faf2SAbhishek Patel timestamp == nullptr || updateTimestamp == nullptr || 20119017faf2SAbhishek Patel notify == nullptr) 2012f86bb901SAdriana Kobylak { 2013ae34c8e8SAdriana Kobylak messages::internalError(asyncResp->res); 2014271584abSEd Tanous return; 2015271584abSEd Tanous } 20169017faf2SAbhishek Patel 2017f86bb901SAdriana Kobylak asyncResp->res.jsonValue["@odata.type"] = 20189c11a172SVijay Lobo "#LogEntry.v1_9_0.LogEntry"; 2019ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 2020ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}", 2021ef4c65b7SEd Tanous std::to_string(*id)); 202245ca1b86SEd Tanous asyncResp->res.jsonValue["Name"] = "System Event Log Entry"; 2023f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Id"] = std::to_string(*id); 2024f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Message"] = *message; 2025f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Resolved"] = resolved; 20269017faf2SAbhishek Patel std::optional<bool> notifyAction = getProviderNotifyAction(*notify); 20279017faf2SAbhishek Patel if (notifyAction) 20289017faf2SAbhishek Patel { 20299017faf2SAbhishek Patel asyncResp->res.jsonValue["ServiceProviderNotified"] = 20309017faf2SAbhishek Patel *notifyAction; 20319017faf2SAbhishek Patel } 20329c11a172SVijay Lobo if ((resolution != nullptr) && (!(*resolution).empty())) 20339c11a172SVijay Lobo { 20349c11a172SVijay Lobo asyncResp->res.jsonValue["Resolution"] = *resolution; 20359c11a172SVijay Lobo } 2036f86bb901SAdriana Kobylak asyncResp->res.jsonValue["EntryType"] = "Event"; 2037f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Severity"] = 2038f86bb901SAdriana Kobylak translateSeverityDbusToRedfish(*severity); 2039f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Created"] = 20402b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*timestamp); 2041f86bb901SAdriana Kobylak asyncResp->res.jsonValue["Modified"] = 20422b82937eSEd Tanous redfish::time_utils::getDateTimeUintMs(*updateTimestamp); 2043f86bb901SAdriana Kobylak if (filePath != nullptr) 2044f86bb901SAdriana Kobylak { 2045f86bb901SAdriana Kobylak asyncResp->res.jsonValue["AdditionalDataURI"] = 2046e7dbd530SPotin Lai "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + 2047e7dbd530SPotin Lai std::to_string(*id) + "/attachment"; 2048f86bb901SAdriana Kobylak } 2049d1bde9e5SKrzysztof Grobelny }); 20507e860f15SJohn Edward Broadbent }); 2051336e96c6SChicago Duan 20527e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 205322d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2054ed398213SEd Tanous .privileges(redfish::privileges::patchLogEntry) 20557e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 205645ca1b86SEd Tanous [&app](const crow::Request& req, 20577e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 205822d268cbSEd Tanous const std::string& systemName, const std::string& entryId) { 20593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 206045ca1b86SEd Tanous { 206145ca1b86SEd Tanous return; 206245ca1b86SEd Tanous } 20637f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 20647f3e84a1SEd Tanous { 20657f3e84a1SEd Tanous // Option currently returns no systems. TBD 20667f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 20677f3e84a1SEd Tanous systemName); 20687f3e84a1SEd Tanous return; 20697f3e84a1SEd Tanous } 207022d268cbSEd Tanous if (systemName != "system") 207122d268cbSEd Tanous { 207222d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 207322d268cbSEd Tanous systemName); 207422d268cbSEd Tanous return; 207522d268cbSEd Tanous } 207675710de2SXiaochao Ma std::optional<bool> resolved; 207775710de2SXiaochao Ma 207815ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved", 20797e860f15SJohn Edward Broadbent resolved)) 208075710de2SXiaochao Ma { 208175710de2SXiaochao Ma return; 208275710de2SXiaochao Ma } 208362598e31SEd Tanous BMCWEB_LOG_DEBUG("Set Resolved"); 208475710de2SXiaochao Ma 20859ae226faSGeorge Liu sdbusplus::asio::setProperty( 20869ae226faSGeorge Liu *crow::connections::systemBus, "xyz.openbmc_project.Logging", 20879ae226faSGeorge Liu "/xyz/openbmc_project/logging/entry/" + entryId, 20889ae226faSGeorge Liu "xyz.openbmc_project.Logging.Entry", "Resolved", *resolved, 20895e7e2dc5SEd Tanous [asyncResp, entryId](const boost::system::error_code& ec) { 209075710de2SXiaochao Ma if (ec) 209175710de2SXiaochao Ma { 209262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 209375710de2SXiaochao Ma messages::internalError(asyncResp->res); 209475710de2SXiaochao Ma return; 209575710de2SXiaochao Ma } 20969ae226faSGeorge Liu }); 20977e860f15SJohn Edward Broadbent }); 209875710de2SXiaochao Ma 20997e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 210022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/") 2101ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 2102ed398213SEd Tanous 2103002d39b4SEd Tanous .methods(boost::beast::http::verb::delete_)( 2104002d39b4SEd Tanous [&app](const crow::Request& req, 2105002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 210622d268cbSEd Tanous const std::string& systemName, const std::string& param) { 21073ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2108336e96c6SChicago Duan { 210945ca1b86SEd Tanous return; 211045ca1b86SEd Tanous } 21117f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 21127f3e84a1SEd Tanous { 21137f3e84a1SEd Tanous // Option currently returns no systems. TBD 21147f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 21157f3e84a1SEd Tanous systemName); 21167f3e84a1SEd Tanous return; 21177f3e84a1SEd Tanous } 211822d268cbSEd Tanous if (systemName != "system") 211922d268cbSEd Tanous { 212022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 212122d268cbSEd Tanous systemName); 212222d268cbSEd Tanous return; 212322d268cbSEd Tanous } 212462598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete single event entries."); 2125336e96c6SChicago Duan 21267e860f15SJohn Edward Broadbent std::string entryID = param; 2127336e96c6SChicago Duan 2128336e96c6SChicago Duan dbus::utility::escapePathForDbus(entryID); 2129336e96c6SChicago Duan 2130336e96c6SChicago Duan // Process response from Logging service. 21315a39f77aSPatrick Williams auto respHandler = [asyncResp, 21325a39f77aSPatrick Williams entryID](const boost::system::error_code& ec) { 213362598e31SEd Tanous BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done"); 2134336e96c6SChicago Duan if (ec) 2135336e96c6SChicago Duan { 21363de8d8baSGeorge Liu if (ec.value() == EBADR) 21373de8d8baSGeorge Liu { 213845ca1b86SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 213945ca1b86SEd Tanous entryID); 21403de8d8baSGeorge Liu return; 21413de8d8baSGeorge Liu } 2142336e96c6SChicago Duan // TODO Handle for specific error code 214362598e31SEd Tanous BMCWEB_LOG_ERROR( 214462598e31SEd Tanous "EventLogEntry (DBus) doDelete respHandler got error {}", 214562598e31SEd Tanous ec); 2146336e96c6SChicago Duan asyncResp->res.result( 2147336e96c6SChicago Duan boost::beast::http::status::internal_server_error); 2148336e96c6SChicago Duan return; 2149336e96c6SChicago Duan } 2150336e96c6SChicago Duan 2151336e96c6SChicago Duan asyncResp->res.result(boost::beast::http::status::ok); 2152336e96c6SChicago Duan }; 2153336e96c6SChicago Duan 2154336e96c6SChicago Duan // Make call to Logging service to request Delete Log 2155336e96c6SChicago Duan crow::connections::systemBus->async_method_call( 2156336e96c6SChicago Duan respHandler, "xyz.openbmc_project.Logging", 2157336e96c6SChicago Duan "/xyz/openbmc_project/logging/entry/" + entryID, 2158336e96c6SChicago Duan "xyz.openbmc_project.Object.Delete", "Delete"); 21597e860f15SJohn Edward Broadbent }); 2160400fd1fbSAdriana Kobylak } 2161400fd1fbSAdriana Kobylak 2162b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console"; 2163b7028ebfSSpencer Ku 2164b7028ebfSSpencer Ku inline bool 2165b7028ebfSSpencer Ku getHostLoggerFiles(const std::string& hostLoggerFilePath, 2166b7028ebfSSpencer Ku std::vector<std::filesystem::path>& hostLoggerFiles) 2167b7028ebfSSpencer Ku { 2168b7028ebfSSpencer Ku std::error_code ec; 2169b7028ebfSSpencer Ku std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec); 2170b7028ebfSSpencer Ku if (ec) 2171b7028ebfSSpencer Ku { 2172bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("{}", ec.message()); 2173b7028ebfSSpencer Ku return false; 2174b7028ebfSSpencer Ku } 2175b7028ebfSSpencer Ku for (const std::filesystem::directory_entry& it : logPath) 2176b7028ebfSSpencer Ku { 2177b7028ebfSSpencer Ku std::string filename = it.path().filename(); 2178b7028ebfSSpencer Ku // Prefix of each log files is "log". Find the file and save the 2179b7028ebfSSpencer Ku // path 218011ba3979SEd Tanous if (filename.starts_with("log")) 2181b7028ebfSSpencer Ku { 2182b7028ebfSSpencer Ku hostLoggerFiles.emplace_back(it.path()); 2183b7028ebfSSpencer Ku } 2184b7028ebfSSpencer Ku } 2185b7028ebfSSpencer Ku // As the log files rotate, they are appended with a ".#" that is higher for 2186b7028ebfSSpencer Ku // the older logs. Since we start from oldest logs, sort the name in 2187b7028ebfSSpencer Ku // descending order. 2188b7028ebfSSpencer Ku std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(), 2189b7028ebfSSpencer Ku AlphanumLess<std::string>()); 2190b7028ebfSSpencer Ku 2191b7028ebfSSpencer Ku return true; 2192b7028ebfSSpencer Ku } 2193b7028ebfSSpencer Ku 219402cad96eSEd Tanous inline bool getHostLoggerEntries( 219502cad96eSEd Tanous const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip, 219602cad96eSEd Tanous uint64_t top, std::vector<std::string>& logEntries, size_t& logCount) 2197b7028ebfSSpencer Ku { 2198b7028ebfSSpencer Ku GzFileReader logFile; 2199b7028ebfSSpencer Ku 2200b7028ebfSSpencer Ku // Go though all log files and expose host logs. 2201b7028ebfSSpencer Ku for (const std::filesystem::path& it : hostLoggerFiles) 2202b7028ebfSSpencer Ku { 2203b7028ebfSSpencer Ku if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount)) 2204b7028ebfSSpencer Ku { 220562598e31SEd Tanous BMCWEB_LOG_ERROR("fail to expose host logs"); 2206b7028ebfSSpencer Ku return false; 2207b7028ebfSSpencer Ku } 2208b7028ebfSSpencer Ku } 2209b7028ebfSSpencer Ku // Get lastMessage from constructor by getter 2210b7028ebfSSpencer Ku std::string lastMessage = logFile.getLastMessage(); 2211b7028ebfSSpencer Ku if (!lastMessage.empty()) 2212b7028ebfSSpencer Ku { 2213b7028ebfSSpencer Ku logCount++; 2214b7028ebfSSpencer Ku if (logCount > skip && logCount <= (skip + top)) 2215b7028ebfSSpencer Ku { 2216b7028ebfSSpencer Ku logEntries.push_back(lastMessage); 2217b7028ebfSSpencer Ku } 2218b7028ebfSSpencer Ku } 2219b7028ebfSSpencer Ku return true; 2220b7028ebfSSpencer Ku } 2221b7028ebfSSpencer Ku 2222b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID, 2223b7028ebfSSpencer Ku const std::string& msg, 22246d6574c9SJason M. Bills nlohmann::json::object_t& logEntryJson) 2225b7028ebfSSpencer Ku { 2226b7028ebfSSpencer Ku // Fill in the log entry with the gathered data. 22279c11a172SVijay Lobo logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2228ef4c65b7SEd Tanous logEntryJson["@odata.id"] = boost::urls::format( 2229ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}", 2230ef4c65b7SEd Tanous logEntryID); 22316d6574c9SJason M. Bills logEntryJson["Name"] = "Host Logger Entry"; 22326d6574c9SJason M. Bills logEntryJson["Id"] = logEntryID; 22336d6574c9SJason M. Bills logEntryJson["Message"] = msg; 22346d6574c9SJason M. Bills logEntryJson["EntryType"] = "Oem"; 22356d6574c9SJason M. Bills logEntryJson["Severity"] = "OK"; 22366d6574c9SJason M. Bills logEntryJson["OemRecordFormat"] = "Host Logger Entry"; 2237b7028ebfSSpencer Ku } 2238b7028ebfSSpencer Ku 2239b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app) 2240b7028ebfSSpencer Ku { 224122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/") 2242b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogService) 22431476687dSEd Tanous .methods(boost::beast::http::verb::get)( 22441476687dSEd Tanous [&app](const crow::Request& req, 224522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 224622d268cbSEd Tanous const std::string& systemName) { 22473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 224845ca1b86SEd Tanous { 224945ca1b86SEd Tanous return; 225045ca1b86SEd Tanous } 22517f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22527f3e84a1SEd Tanous { 22537f3e84a1SEd Tanous // Option currently returns no systems. TBD 22547f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22557f3e84a1SEd Tanous systemName); 22567f3e84a1SEd Tanous return; 22577f3e84a1SEd Tanous } 225822d268cbSEd Tanous if (systemName != "system") 225922d268cbSEd Tanous { 226022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 226122d268cbSEd Tanous systemName); 226222d268cbSEd Tanous return; 226322d268cbSEd Tanous } 2264b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2265b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger"; 2266b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2267b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 2268b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "Host Logger Service"; 2269b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = "Host Logger Service"; 2270b7028ebfSSpencer Ku asyncResp->res.jsonValue["Id"] = "HostLogger"; 22711476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 22721476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2273b7028ebfSSpencer Ku }); 2274b7028ebfSSpencer Ku } 2275b7028ebfSSpencer Ku 2276b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app) 2277b7028ebfSSpencer Ku { 2278b7028ebfSSpencer Ku BMCWEB_ROUTE(app, 227922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/") 2280b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2281002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2282002d39b4SEd Tanous [&app](const crow::Request& req, 228322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 228422d268cbSEd Tanous const std::string& systemName) { 2285c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2286c937d2bfSEd Tanous .canDelegateTop = true, 2287c937d2bfSEd Tanous .canDelegateSkip = true, 2288c937d2bfSEd Tanous }; 2289c937d2bfSEd Tanous query_param::Query delegatedQuery; 2290c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 22913ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2292b7028ebfSSpencer Ku { 2293b7028ebfSSpencer Ku return; 2294b7028ebfSSpencer Ku } 22957f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 22967f3e84a1SEd Tanous { 22977f3e84a1SEd Tanous // Option currently returns no systems. TBD 22987f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 22997f3e84a1SEd Tanous systemName); 23007f3e84a1SEd Tanous return; 23017f3e84a1SEd Tanous } 230222d268cbSEd Tanous if (systemName != "system") 230322d268cbSEd Tanous { 230422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 230522d268cbSEd Tanous systemName); 230622d268cbSEd Tanous return; 230722d268cbSEd Tanous } 2308b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.id"] = 2309b7028ebfSSpencer Ku "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"; 2310b7028ebfSSpencer Ku asyncResp->res.jsonValue["@odata.type"] = 2311b7028ebfSSpencer Ku "#LogEntryCollection.LogEntryCollection"; 2312b7028ebfSSpencer Ku asyncResp->res.jsonValue["Name"] = "HostLogger Entries"; 2313b7028ebfSSpencer Ku asyncResp->res.jsonValue["Description"] = 2314b7028ebfSSpencer Ku "Collection of HostLogger Entries"; 23150fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2316b7028ebfSSpencer Ku logEntryArray = nlohmann::json::array(); 2317b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = 0; 2318b7028ebfSSpencer Ku 2319b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2320b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2321b7028ebfSSpencer Ku { 2322bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2323b7028ebfSSpencer Ku return; 2324b7028ebfSSpencer Ku } 23253648c8beSEd Tanous // If we weren't provided top and skip limits, use the defaults. 23263648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 23275143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 2328b7028ebfSSpencer Ku size_t logCount = 0; 2329b7028ebfSSpencer Ku // This vector only store the entries we want to expose that 2330b7028ebfSSpencer Ku // control by skip and top. 2331b7028ebfSSpencer Ku std::vector<std::string> logEntries; 23323648c8beSEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, 23333648c8beSEd Tanous logCount)) 2334b7028ebfSSpencer Ku { 2335b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2336b7028ebfSSpencer Ku return; 2337b7028ebfSSpencer Ku } 2338b7028ebfSSpencer Ku // If vector is empty, that means skip value larger than total 2339b7028ebfSSpencer Ku // log count 234026f6976fSEd Tanous if (logEntries.empty()) 2341b7028ebfSSpencer Ku { 2342b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 2343b7028ebfSSpencer Ku return; 2344b7028ebfSSpencer Ku } 234526f6976fSEd Tanous if (!logEntries.empty()) 2346b7028ebfSSpencer Ku { 2347b7028ebfSSpencer Ku for (size_t i = 0; i < logEntries.size(); i++) 2348b7028ebfSSpencer Ku { 23496d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 23503648c8beSEd Tanous fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i], 23513648c8beSEd Tanous hostLogEntry); 2352b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(hostLogEntry)); 2353b7028ebfSSpencer Ku } 2354b7028ebfSSpencer Ku 2355b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.count"] = logCount; 23563648c8beSEd Tanous if (skip + top < logCount) 2357b7028ebfSSpencer Ku { 2358b7028ebfSSpencer Ku asyncResp->res.jsonValue["Members@odata.nextLink"] = 23590fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" + 23603648c8beSEd Tanous std::to_string(skip + top); 2361b7028ebfSSpencer Ku } 2362b7028ebfSSpencer Ku } 2363b7028ebfSSpencer Ku }); 2364b7028ebfSSpencer Ku } 2365b7028ebfSSpencer Ku 2366b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app) 2367b7028ebfSSpencer Ku { 2368b7028ebfSSpencer Ku BMCWEB_ROUTE( 236922d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/") 2370b7028ebfSSpencer Ku .privileges(redfish::privileges::getLogEntry) 2371b7028ebfSSpencer Ku .methods(boost::beast::http::verb::get)( 237245ca1b86SEd Tanous [&app](const crow::Request& req, 2373b7028ebfSSpencer Ku const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 237422d268cbSEd Tanous const std::string& systemName, const std::string& param) { 23753ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 237645ca1b86SEd Tanous { 237745ca1b86SEd Tanous return; 237845ca1b86SEd Tanous } 23797f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 23807f3e84a1SEd Tanous { 23817f3e84a1SEd Tanous // Option currently returns no systems. TBD 23827f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 23837f3e84a1SEd Tanous systemName); 23847f3e84a1SEd Tanous return; 23857f3e84a1SEd Tanous } 238622d268cbSEd Tanous if (systemName != "system") 238722d268cbSEd Tanous { 238822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 238922d268cbSEd Tanous systemName); 239022d268cbSEd Tanous return; 239122d268cbSEd Tanous } 2392b7028ebfSSpencer Ku const std::string& targetID = param; 2393b7028ebfSSpencer Ku 2394b7028ebfSSpencer Ku uint64_t idInt = 0; 2395ca45aa3cSEd Tanous 239684396af9SPatrick Williams auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(), 239784396af9SPatrick Williams idInt); 23989db4ba25SJiaqing Zhao if (ec == std::errc::invalid_argument || 23999db4ba25SJiaqing Zhao ec == std::errc::result_out_of_range) 2400b7028ebfSSpencer Ku { 24019db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2402b7028ebfSSpencer Ku return; 2403b7028ebfSSpencer Ku } 2404b7028ebfSSpencer Ku 2405b7028ebfSSpencer Ku std::vector<std::filesystem::path> hostLoggerFiles; 2406b7028ebfSSpencer Ku if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles)) 2407b7028ebfSSpencer Ku { 2408bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to get host log file path"); 2409b7028ebfSSpencer Ku return; 2410b7028ebfSSpencer Ku } 2411b7028ebfSSpencer Ku 2412b7028ebfSSpencer Ku size_t logCount = 0; 24133648c8beSEd Tanous size_t top = 1; 2414b7028ebfSSpencer Ku std::vector<std::string> logEntries; 2415b7028ebfSSpencer Ku // We can get specific entry by skip and top. For example, if we 2416b7028ebfSSpencer Ku // want to get nth entry, we can set skip = n-1 and top = 1 to 2417b7028ebfSSpencer Ku // get that entry 2418002d39b4SEd Tanous if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries, 2419002d39b4SEd Tanous logCount)) 2420b7028ebfSSpencer Ku { 2421b7028ebfSSpencer Ku messages::internalError(asyncResp->res); 2422b7028ebfSSpencer Ku return; 2423b7028ebfSSpencer Ku } 2424b7028ebfSSpencer Ku 2425b7028ebfSSpencer Ku if (!logEntries.empty()) 2426b7028ebfSSpencer Ku { 24276d6574c9SJason M. Bills nlohmann::json::object_t hostLogEntry; 24286d6574c9SJason M. Bills fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry); 24296d6574c9SJason M. Bills asyncResp->res.jsonValue.update(hostLogEntry); 2430b7028ebfSSpencer Ku return; 2431b7028ebfSSpencer Ku } 2432b7028ebfSSpencer Ku 2433b7028ebfSSpencer Ku // Requested ID was not found 24349db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", param); 2435b7028ebfSSpencer Ku }); 2436b7028ebfSSpencer Ku } 2437b7028ebfSSpencer Ku 2438dd72e87bSClaire Weinan inline void handleBMCLogServicesCollectionGet( 2439fdd26906SClaire Weinan crow::App& app, const crow::Request& req, 2440fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 24411da66f75SEd Tanous { 24423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 244345ca1b86SEd Tanous { 244445ca1b86SEd Tanous return; 244545ca1b86SEd Tanous } 24467e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 24477e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2448e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 24491da66f75SEd Tanous "#LogServiceCollection.LogServiceCollection"; 2450e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.id"] = 2451e1f26343SJason M. Bills "/redfish/v1/Managers/bmc/LogServices"; 2452002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection"; 2453e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 24541da66f75SEd Tanous "Collection of LogServices for this Manager"; 2455002d39b4SEd Tanous nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"]; 2456c4bf6374SJason M. Bills logServiceArray = nlohmann::json::array(); 2457fdd26906SClaire Weinan 2458c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL 2459613dabeaSEd Tanous nlohmann::json::object_t journal; 2460613dabeaSEd Tanous journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal"; 2461b2ba3072SPatrick Williams logServiceArray.emplace_back(std::move(journal)); 2462c4bf6374SJason M. Bills #endif 2463fdd26906SClaire Weinan 2464fdd26906SClaire Weinan asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size(); 2465fdd26906SClaire Weinan 2466fdd26906SClaire Weinan #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG 246715912159SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 24687a1dbc48SGeorge Liu "xyz.openbmc_project.Collection.DeleteAll"}; 24697a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 24707a1dbc48SGeorge Liu "/xyz/openbmc_project/dump", 0, interfaces, 2471fdd26906SClaire Weinan [asyncResp]( 24727a1dbc48SGeorge Liu const boost::system::error_code& ec, 2473fdd26906SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 2474fdd26906SClaire Weinan if (ec) 2475fdd26906SClaire Weinan { 247662598e31SEd Tanous BMCWEB_LOG_ERROR( 247762598e31SEd Tanous "handleBMCLogServicesCollectionGet respHandler got error {}", 247862598e31SEd Tanous ec); 2479fdd26906SClaire Weinan // Assume that getting an error simply means there are no dump 2480fdd26906SClaire Weinan // LogServices. Return without adding any error response. 2481fdd26906SClaire Weinan return; 2482fdd26906SClaire Weinan } 2483fdd26906SClaire Weinan 2484fdd26906SClaire Weinan nlohmann::json& logServiceArrayLocal = 2485fdd26906SClaire Weinan asyncResp->res.jsonValue["Members"]; 2486fdd26906SClaire Weinan 2487fdd26906SClaire Weinan for (const std::string& path : subTreePaths) 2488fdd26906SClaire Weinan { 2489fdd26906SClaire Weinan if (path == "/xyz/openbmc_project/dump/bmc") 2490fdd26906SClaire Weinan { 2491613dabeaSEd Tanous nlohmann::json::object_t member; 2492613dabeaSEd Tanous member["@odata.id"] = 2493613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Dump"; 2494b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2495fdd26906SClaire Weinan } 2496fdd26906SClaire Weinan else if (path == "/xyz/openbmc_project/dump/faultlog") 2497fdd26906SClaire Weinan { 2498613dabeaSEd Tanous nlohmann::json::object_t member; 2499613dabeaSEd Tanous member["@odata.id"] = 2500613dabeaSEd Tanous "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2501b2ba3072SPatrick Williams logServiceArrayLocal.emplace_back(std::move(member)); 2502fdd26906SClaire Weinan } 2503fdd26906SClaire Weinan } 2504fdd26906SClaire Weinan 2505e1f26343SJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 2506fdd26906SClaire Weinan logServiceArrayLocal.size(); 25077a1dbc48SGeorge Liu }); 2508fdd26906SClaire Weinan #endif 2509fdd26906SClaire Weinan } 2510fdd26906SClaire Weinan 2511fdd26906SClaire Weinan inline void requestRoutesBMCLogServiceCollection(App& app) 2512fdd26906SClaire Weinan { 2513fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/") 2514fdd26906SClaire Weinan .privileges(redfish::privileges::getLogServiceCollection) 2515fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 2516dd72e87bSClaire Weinan std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app))); 2517e1f26343SJason M. Bills } 2518e1f26343SJason M. Bills 25197e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app) 2520e1f26343SJason M. Bills { 25217e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/") 2522ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 25237e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 252445ca1b86SEd Tanous [&app](const crow::Request& req, 252545ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 25263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25277e860f15SJohn Edward Broadbent { 252845ca1b86SEd Tanous return; 252945ca1b86SEd Tanous } 2530e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2531b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 25320f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 25330f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal"; 2534002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service"; 2535002d39b4SEd Tanous asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service"; 2536ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "Journal"; 2537e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 25387c8c4058STejas Patil 25397c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 25402b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 2541002d39b4SEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 25427c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 25437c8c4058STejas Patil redfishDateTimeOffset.second; 25447c8c4058STejas Patil 25451476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 25461476687dSEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 25477e860f15SJohn Edward Broadbent }); 2548e1f26343SJason M. Bills } 2549e1f26343SJason M. Bills 25503a48b3a2SJason M. Bills static int 25513a48b3a2SJason M. Bills fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID, 2552e1f26343SJason M. Bills sd_journal* journal, 25533a48b3a2SJason M. Bills nlohmann::json::object_t& bmcJournalLogEntryJson) 2554e1f26343SJason M. Bills { 2555e1f26343SJason M. Bills // Get the Log Entry contents 2556e1f26343SJason M. Bills int ret = 0; 2557e1f26343SJason M. Bills 2558a8fe54f0SJason M. Bills std::string message; 2559a8fe54f0SJason M. Bills std::string_view syslogID; 2560a8fe54f0SJason M. Bills ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 2561a8fe54f0SJason M. Bills if (ret < 0) 2562a8fe54f0SJason M. Bills { 2563bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", 256462598e31SEd Tanous strerror(-ret)); 2565a8fe54f0SJason M. Bills } 2566a8fe54f0SJason M. Bills if (!syslogID.empty()) 2567a8fe54f0SJason M. Bills { 2568a8fe54f0SJason M. Bills message += std::string(syslogID) + ": "; 2569a8fe54f0SJason M. Bills } 2570a8fe54f0SJason M. Bills 257139e77504SEd Tanous std::string_view msg; 257216428a1aSJason M. Bills ret = getJournalMetadata(journal, "MESSAGE", msg); 2573e1f26343SJason M. Bills if (ret < 0) 2574e1f26343SJason M. Bills { 257562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret)); 2576e1f26343SJason M. Bills return 1; 2577e1f26343SJason M. Bills } 2578a8fe54f0SJason M. Bills message += std::string(msg); 2579e1f26343SJason M. Bills 2580e1f26343SJason M. Bills // Get the severity from the PRIORITY field 2581271584abSEd Tanous long int severity = 8; // Default to an invalid priority 258216428a1aSJason M. Bills ret = getJournalMetadata(journal, "PRIORITY", 10, severity); 2583e1f26343SJason M. Bills if (ret < 0) 2584e1f26343SJason M. Bills { 2585bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret)); 2586e1f26343SJason M. Bills } 2587e1f26343SJason M. Bills 2588e1f26343SJason M. Bills // Get the Created time from the timestamp 258916428a1aSJason M. Bills std::string entryTimeStr; 259016428a1aSJason M. Bills if (!getEntryTimestamp(journal, entryTimeStr)) 2591e1f26343SJason M. Bills { 259216428a1aSJason M. Bills return 1; 2593e1f26343SJason M. Bills } 2594e1f26343SJason M. Bills 2595e1f26343SJason M. Bills // Fill in the log entry with the gathered data 25969c11a172SVijay Lobo bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 2597ef4c65b7SEd Tanous bmcJournalLogEntryJson["@odata.id"] = boost::urls::format( 2598ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}", 2599eddfc437SWilly Tu bmcJournalLogEntryID); 260084afc48bSJason M. Bills bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 260184afc48bSJason M. Bills bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID; 260284afc48bSJason M. Bills bmcJournalLogEntryJson["Message"] = std::move(message); 260384afc48bSJason M. Bills bmcJournalLogEntryJson["EntryType"] = "Oem"; 260484afc48bSJason M. Bills bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical" 2605738c1e61SPatrick Williams : severity <= 4 ? "Warning" 260684afc48bSJason M. Bills : "OK"; 260784afc48bSJason M. Bills bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 260884afc48bSJason M. Bills bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 2609e1f26343SJason M. Bills return 0; 2610e1f26343SJason M. Bills } 2611e1f26343SJason M. Bills 26127e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app) 2613e1f26343SJason M. Bills { 26147e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/") 2615ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 2616002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 2617002d39b4SEd Tanous [&app](const crow::Request& req, 2618002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2619c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 2620c937d2bfSEd Tanous .canDelegateTop = true, 2621c937d2bfSEd Tanous .canDelegateSkip = true, 2622c937d2bfSEd Tanous }; 2623c937d2bfSEd Tanous query_param::Query delegatedQuery; 2624c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 26253ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 2626193ad2faSJason M. Bills { 2627193ad2faSJason M. Bills return; 2628193ad2faSJason M. Bills } 26293648c8beSEd Tanous 26303648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 26315143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 26323648c8beSEd Tanous 26337e860f15SJohn Edward Broadbent // Collections don't include the static data added by SubRoute 26347e860f15SJohn Edward Broadbent // because it has a duplicate entry for members 2635e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 2636e1f26343SJason M. Bills "#LogEntryCollection.LogEntryCollection"; 26370f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 26380f74e643SEd Tanous "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"; 2639e1f26343SJason M. Bills asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries"; 2640e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 2641e1f26343SJason M. Bills "Collection of BMC Journal Entries"; 26420fda0f12SGeorge Liu nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 2643e1f26343SJason M. Bills logEntryArray = nlohmann::json::array(); 2644e1f26343SJason M. Bills 26457e860f15SJohn Edward Broadbent // Go through the journal and use the timestamp to create a 26467e860f15SJohn Edward Broadbent // unique ID for each entry 2647e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2648e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2649e1f26343SJason M. Bills if (ret < 0) 2650e1f26343SJason M. Bills { 265162598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2652f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2653e1f26343SJason M. Bills return; 2654e1f26343SJason M. Bills } 26550fda0f12SGeorge Liu std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 26560fda0f12SGeorge Liu journalTmp, sd_journal_close); 2657e1f26343SJason M. Bills journalTmp = nullptr; 2658b01bf299SEd Tanous uint64_t entryCount = 0; 2659e85d6b16SJason M. Bills // Reset the unique ID on the first entry 2660e85d6b16SJason M. Bills bool firstEntry = true; 2661e1f26343SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 2662e1f26343SJason M. Bills { 2663193ad2faSJason M. Bills entryCount++; 26647e860f15SJohn Edward Broadbent // Handle paging using skip (number of entries to skip from 26657e860f15SJohn Edward Broadbent // the start) and top (number of entries to display) 26663648c8beSEd Tanous if (entryCount <= skip || entryCount > skip + top) 2667193ad2faSJason M. Bills { 2668193ad2faSJason M. Bills continue; 2669193ad2faSJason M. Bills } 2670193ad2faSJason M. Bills 267116428a1aSJason M. Bills std::string idStr; 2672e85d6b16SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2673e1f26343SJason M. Bills { 2674e1f26343SJason M. Bills continue; 2675e1f26343SJason M. Bills } 2676e85d6b16SJason M. Bills firstEntry = false; 2677e85d6b16SJason M. Bills 26783a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2679c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(idStr, journal.get(), 2680c4bf6374SJason M. Bills bmcJournalLogEntry) != 0) 2681e1f26343SJason M. Bills { 2682f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2683e1f26343SJason M. Bills return; 2684e1f26343SJason M. Bills } 2685b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcJournalLogEntry)); 2686e1f26343SJason M. Bills } 2687193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = entryCount; 26883648c8beSEd Tanous if (skip + top < entryCount) 2689193ad2faSJason M. Bills { 2690193ad2faSJason M. Bills asyncResp->res.jsonValue["Members@odata.nextLink"] = 26910fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" + 26923648c8beSEd Tanous std::to_string(skip + top); 2693193ad2faSJason M. Bills } 26947e860f15SJohn Edward Broadbent }); 2695e1f26343SJason M. Bills } 2696e1f26343SJason M. Bills 26977e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app) 2698e1f26343SJason M. Bills { 26997e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 27007e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/") 2701ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 27027e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 270345ca1b86SEd Tanous [&app](const crow::Request& req, 27047e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27057e860f15SJohn Edward Broadbent const std::string& entryID) { 27063ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 270745ca1b86SEd Tanous { 270845ca1b86SEd Tanous return; 270945ca1b86SEd Tanous } 2710e1f26343SJason M. Bills // Convert the unique ID back to a timestamp to find the entry 2711*75e8e218SMyung Bae sd_id128_t bootID{}; 2712e1f26343SJason M. Bills uint64_t ts = 0; 2713271584abSEd Tanous uint64_t index = 0; 2714*75e8e218SMyung Bae if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index)) 2715e1f26343SJason M. Bills { 271616428a1aSJason M. Bills return; 2717e1f26343SJason M. Bills } 2718e1f26343SJason M. Bills 2719e1f26343SJason M. Bills sd_journal* journalTmp = nullptr; 2720e1f26343SJason M. Bills int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); 2721e1f26343SJason M. Bills if (ret < 0) 2722e1f26343SJason M. Bills { 272362598e31SEd Tanous BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret)); 2724f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2725e1f26343SJason M. Bills return; 2726e1f26343SJason M. Bills } 2727002d39b4SEd Tanous std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 2728002d39b4SEd Tanous journalTmp, sd_journal_close); 2729e1f26343SJason M. Bills journalTmp = nullptr; 27307e860f15SJohn Edward Broadbent // Go to the timestamp in the log and move to the entry at the 27317e860f15SJohn Edward Broadbent // index tracking the unique ID 2732af07e3f5SJason M. Bills std::string idStr; 2733af07e3f5SJason M. Bills bool firstEntry = true; 2734*75e8e218SMyung Bae ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts); 27352056b6d1SManojkiran Eda if (ret < 0) 27362056b6d1SManojkiran Eda { 273762598e31SEd Tanous BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}", 273862598e31SEd Tanous strerror(-ret)); 27392056b6d1SManojkiran Eda messages::internalError(asyncResp->res); 27402056b6d1SManojkiran Eda return; 27412056b6d1SManojkiran Eda } 2742271584abSEd Tanous for (uint64_t i = 0; i <= index; i++) 2743e1f26343SJason M. Bills { 2744e1f26343SJason M. Bills sd_journal_next(journal.get()); 2745af07e3f5SJason M. Bills if (!getUniqueEntryID(journal.get(), idStr, firstEntry)) 2746af07e3f5SJason M. Bills { 2747af07e3f5SJason M. Bills messages::internalError(asyncResp->res); 2748af07e3f5SJason M. Bills return; 2749af07e3f5SJason M. Bills } 2750af07e3f5SJason M. Bills firstEntry = false; 2751af07e3f5SJason M. Bills } 2752c4bf6374SJason M. Bills // Confirm that the entry ID matches what was requested 2753af07e3f5SJason M. Bills if (idStr != entryID) 2754c4bf6374SJason M. Bills { 27559db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", entryID); 2756c4bf6374SJason M. Bills return; 2757c4bf6374SJason M. Bills } 2758c4bf6374SJason M. Bills 27593a48b3a2SJason M. Bills nlohmann::json::object_t bmcJournalLogEntry; 2760c4bf6374SJason M. Bills if (fillBMCJournalLogEntryJson(entryID, journal.get(), 27613a48b3a2SJason M. Bills bmcJournalLogEntry) != 0) 2762e1f26343SJason M. Bills { 2763f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2764e1f26343SJason M. Bills return; 2765e1f26343SJason M. Bills } 2766d405bb51SJason M. Bills asyncResp->res.jsonValue.update(bmcJournalLogEntry); 27677e860f15SJohn Edward Broadbent }); 2768c9bb6861Sraviteja-b } 2769c9bb6861Sraviteja-b 2770fdd26906SClaire Weinan inline void 2771fdd26906SClaire Weinan getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2772fdd26906SClaire Weinan const std::string& dumpType) 2773c9bb6861Sraviteja-b { 2774fdd26906SClaire Weinan std::string dumpPath; 2775fdd26906SClaire Weinan std::string overWritePolicy; 2776fdd26906SClaire Weinan bool collectDiagnosticDataSupported = false; 2777fdd26906SClaire Weinan 2778fdd26906SClaire Weinan if (dumpType == "BMC") 277945ca1b86SEd Tanous { 2780fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump"; 2781fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2782fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2783fdd26906SClaire Weinan } 2784fdd26906SClaire Weinan else if (dumpType == "FaultLog") 2785fdd26906SClaire Weinan { 2786fdd26906SClaire Weinan dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog"; 2787fdd26906SClaire Weinan overWritePolicy = "Unknown"; 2788fdd26906SClaire Weinan collectDiagnosticDataSupported = false; 2789fdd26906SClaire Weinan } 2790fdd26906SClaire Weinan else if (dumpType == "System") 2791fdd26906SClaire Weinan { 2792fdd26906SClaire Weinan dumpPath = "/redfish/v1/Systems/system/LogServices/Dump"; 2793fdd26906SClaire Weinan overWritePolicy = "WrapsWhenFull"; 2794fdd26906SClaire Weinan collectDiagnosticDataSupported = true; 2795fdd26906SClaire Weinan } 2796fdd26906SClaire Weinan else 2797fdd26906SClaire Weinan { 279862598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}", 279962598e31SEd Tanous dumpType); 2800fdd26906SClaire Weinan messages::internalError(asyncResp->res); 280145ca1b86SEd Tanous return; 280245ca1b86SEd Tanous } 2803fdd26906SClaire Weinan 2804fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.id"] = dumpPath; 2805fdd26906SClaire Weinan asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService"; 2806c9bb6861Sraviteja-b asyncResp->res.jsonValue["Name"] = "Dump LogService"; 2807fdd26906SClaire Weinan asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService"; 2808fdd26906SClaire Weinan asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename(); 2809fdd26906SClaire Weinan asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy); 28107c8c4058STejas Patil 28117c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 28122b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 28130fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 28147c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 28157c8c4058STejas Patil redfishDateTimeOffset.second; 28167c8c4058STejas Patil 2817fdd26906SClaire Weinan asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries"; 2818fdd26906SClaire Weinan 2819fdd26906SClaire Weinan if (collectDiagnosticDataSupported) 2820fdd26906SClaire Weinan { 2821002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 28221476687dSEd Tanous ["target"] = 2823fdd26906SClaire Weinan dumpPath + "/Actions/LogService.CollectDiagnosticData"; 2824fdd26906SClaire Weinan } 28250d946211SClaire Weinan 28260d946211SClaire Weinan constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface}; 28270d946211SClaire Weinan dbus::utility::getSubTreePaths( 28280d946211SClaire Weinan "/xyz/openbmc_project/dump", 0, interfaces, 28290d946211SClaire Weinan [asyncResp, dumpType, dumpPath]( 28300d946211SClaire Weinan const boost::system::error_code& ec, 28310d946211SClaire Weinan const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) { 28320d946211SClaire Weinan if (ec) 28330d946211SClaire Weinan { 283462598e31SEd Tanous BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec); 28350d946211SClaire Weinan // Assume that getting an error simply means there are no dump 28360d946211SClaire Weinan // LogServices. Return without adding any error response. 28370d946211SClaire Weinan return; 28380d946211SClaire Weinan } 28390d946211SClaire Weinan 28400d946211SClaire Weinan const std::string dbusDumpPath = 28410d946211SClaire Weinan "/xyz/openbmc_project/dump/" + 28420d946211SClaire Weinan boost::algorithm::to_lower_copy(dumpType); 28430d946211SClaire Weinan 28440d946211SClaire Weinan for (const std::string& path : subTreePaths) 28450d946211SClaire Weinan { 28460d946211SClaire Weinan if (path == dbusDumpPath) 28470d946211SClaire Weinan { 28480d946211SClaire Weinan asyncResp->res 28490d946211SClaire Weinan .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 28500d946211SClaire Weinan dumpPath + "/Actions/LogService.ClearLog"; 28510d946211SClaire Weinan break; 28520d946211SClaire Weinan } 28530d946211SClaire Weinan } 28540d946211SClaire Weinan }); 2855c9bb6861Sraviteja-b } 2856c9bb6861Sraviteja-b 2857fdd26906SClaire Weinan inline void handleLogServicesDumpServiceGet( 2858fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2859fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 28607e860f15SJohn Edward Broadbent { 28613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 286245ca1b86SEd Tanous { 286345ca1b86SEd Tanous return; 286445ca1b86SEd Tanous } 2865fdd26906SClaire Weinan getDumpServiceInfo(asyncResp, dumpType); 2866fdd26906SClaire Weinan } 2867c9bb6861Sraviteja-b 286822d268cbSEd Tanous inline void handleLogServicesDumpServiceComputerSystemGet( 286922d268cbSEd Tanous crow::App& app, const crow::Request& req, 287022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 287122d268cbSEd Tanous const std::string& chassisId) 287222d268cbSEd Tanous { 287322d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 287422d268cbSEd Tanous { 287522d268cbSEd Tanous return; 287622d268cbSEd Tanous } 287722d268cbSEd Tanous if (chassisId != "system") 287822d268cbSEd Tanous { 287922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 288022d268cbSEd Tanous return; 288122d268cbSEd Tanous } 288222d268cbSEd Tanous getDumpServiceInfo(asyncResp, "System"); 288322d268cbSEd Tanous } 288422d268cbSEd Tanous 2885fdd26906SClaire Weinan inline void handleLogServicesDumpEntriesCollectionGet( 2886fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2887fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2888fdd26906SClaire Weinan { 2889fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2890fdd26906SClaire Weinan { 2891fdd26906SClaire Weinan return; 2892fdd26906SClaire Weinan } 2893fdd26906SClaire Weinan getDumpEntryCollection(asyncResp, dumpType); 2894fdd26906SClaire Weinan } 2895fdd26906SClaire Weinan 289622d268cbSEd Tanous inline void handleLogServicesDumpEntriesCollectionComputerSystemGet( 289722d268cbSEd Tanous crow::App& app, const crow::Request& req, 289822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 289922d268cbSEd Tanous const std::string& chassisId) 290022d268cbSEd Tanous { 290122d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 290222d268cbSEd Tanous { 290322d268cbSEd Tanous return; 290422d268cbSEd Tanous } 290522d268cbSEd Tanous if (chassisId != "system") 290622d268cbSEd Tanous { 290722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 290822d268cbSEd Tanous return; 290922d268cbSEd Tanous } 291022d268cbSEd Tanous getDumpEntryCollection(asyncResp, "System"); 291122d268cbSEd Tanous } 291222d268cbSEd Tanous 2913fdd26906SClaire Weinan inline void handleLogServicesDumpEntryGet( 2914fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2915fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2916fdd26906SClaire Weinan const std::string& dumpId) 2917fdd26906SClaire Weinan { 2918fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2919fdd26906SClaire Weinan { 2920fdd26906SClaire Weinan return; 2921fdd26906SClaire Weinan } 2922fdd26906SClaire Weinan getDumpEntryById(asyncResp, dumpId, dumpType); 2923fdd26906SClaire Weinan } 2924168d1b1aSCarson Labrado 292522d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemGet( 292622d268cbSEd Tanous crow::App& app, const crow::Request& req, 292722d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 292822d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 292922d268cbSEd Tanous { 293022d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 293122d268cbSEd Tanous { 293222d268cbSEd Tanous return; 293322d268cbSEd Tanous } 293422d268cbSEd Tanous if (chassisId != "system") 293522d268cbSEd Tanous { 293622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 293722d268cbSEd Tanous return; 293822d268cbSEd Tanous } 293922d268cbSEd Tanous getDumpEntryById(asyncResp, dumpId, "System"); 294022d268cbSEd Tanous } 2941fdd26906SClaire Weinan 2942fdd26906SClaire Weinan inline void handleLogServicesDumpEntryDelete( 2943fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 2944fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2945fdd26906SClaire Weinan const std::string& dumpId) 2946fdd26906SClaire Weinan { 2947fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2948fdd26906SClaire Weinan { 2949fdd26906SClaire Weinan return; 2950fdd26906SClaire Weinan } 2951fdd26906SClaire Weinan deleteDumpEntry(asyncResp, dumpId, dumpType); 2952fdd26906SClaire Weinan } 2953fdd26906SClaire Weinan 295422d268cbSEd Tanous inline void handleLogServicesDumpEntryComputerSystemDelete( 295522d268cbSEd Tanous crow::App& app, const crow::Request& req, 295622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 295722d268cbSEd Tanous const std::string& chassisId, const std::string& dumpId) 295822d268cbSEd Tanous { 295922d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 296022d268cbSEd Tanous { 296122d268cbSEd Tanous return; 296222d268cbSEd Tanous } 296322d268cbSEd Tanous if (chassisId != "system") 296422d268cbSEd Tanous { 296522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId); 296622d268cbSEd Tanous return; 296722d268cbSEd Tanous } 296822d268cbSEd Tanous deleteDumpEntry(asyncResp, dumpId, "System"); 296922d268cbSEd Tanous } 297022d268cbSEd Tanous 2971168d1b1aSCarson Labrado inline void handleLogServicesDumpEntryDownloadGet( 2972168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2973168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2974168d1b1aSCarson Labrado const std::string& dumpId) 2975168d1b1aSCarson Labrado { 2976168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2977168d1b1aSCarson Labrado { 2978168d1b1aSCarson Labrado return; 2979168d1b1aSCarson Labrado } 2980168d1b1aSCarson Labrado downloadDumpEntry(asyncResp, dumpId, dumpType); 2981168d1b1aSCarson Labrado } 2982168d1b1aSCarson Labrado 2983168d1b1aSCarson Labrado inline void handleDBusEventLogEntryDownloadGet( 2984168d1b1aSCarson Labrado crow::App& app, const std::string& dumpType, const crow::Request& req, 2985168d1b1aSCarson Labrado const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2986168d1b1aSCarson Labrado const std::string& systemName, const std::string& entryID) 2987168d1b1aSCarson Labrado { 2988168d1b1aSCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2989168d1b1aSCarson Labrado { 2990168d1b1aSCarson Labrado return; 2991168d1b1aSCarson Labrado } 2992168d1b1aSCarson Labrado if (!http_helpers::isContentTypeAllowed( 2993168d1b1aSCarson Labrado req.getHeaderValue("Accept"), 2994168d1b1aSCarson Labrado http_helpers::ContentType::OctetStream, true)) 2995168d1b1aSCarson Labrado { 2996168d1b1aSCarson Labrado asyncResp->res.result(boost::beast::http::status::bad_request); 2997168d1b1aSCarson Labrado return; 2998168d1b1aSCarson Labrado } 2999168d1b1aSCarson Labrado downloadEventLogEntry(asyncResp, systemName, entryID, dumpType); 3000168d1b1aSCarson Labrado } 3001168d1b1aSCarson Labrado 3002fdd26906SClaire Weinan inline void handleLogServicesDumpCollectDiagnosticDataPost( 3003fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3004fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3005fdd26906SClaire Weinan { 3006fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3007fdd26906SClaire Weinan { 3008fdd26906SClaire Weinan return; 3009fdd26906SClaire Weinan } 3010fdd26906SClaire Weinan createDump(asyncResp, req, dumpType); 3011fdd26906SClaire Weinan } 3012fdd26906SClaire Weinan 301322d268cbSEd Tanous inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost( 301422d268cbSEd Tanous crow::App& app, const crow::Request& req, 301522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30167f3e84a1SEd Tanous const std::string& systemName) 301722d268cbSEd Tanous { 301822d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 301922d268cbSEd Tanous { 302022d268cbSEd Tanous return; 302122d268cbSEd Tanous } 30227f3e84a1SEd Tanous 30237f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 302422d268cbSEd Tanous { 30257f3e84a1SEd Tanous // Option currently returns no systems. TBD 30267f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30277f3e84a1SEd Tanous systemName); 30287f3e84a1SEd Tanous return; 30297f3e84a1SEd Tanous } 30307f3e84a1SEd Tanous if (systemName != "system") 30317f3e84a1SEd Tanous { 30327f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30337f3e84a1SEd Tanous systemName); 303422d268cbSEd Tanous return; 303522d268cbSEd Tanous } 303622d268cbSEd Tanous createDump(asyncResp, req, "System"); 303722d268cbSEd Tanous } 303822d268cbSEd Tanous 3039fdd26906SClaire Weinan inline void handleLogServicesDumpClearLogPost( 3040fdd26906SClaire Weinan crow::App& app, const std::string& dumpType, const crow::Request& req, 3041fdd26906SClaire Weinan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3042fdd26906SClaire Weinan { 3043fdd26906SClaire Weinan if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3044fdd26906SClaire Weinan { 3045fdd26906SClaire Weinan return; 3046fdd26906SClaire Weinan } 3047fdd26906SClaire Weinan clearDump(asyncResp, dumpType); 3048fdd26906SClaire Weinan } 3049fdd26906SClaire Weinan 305022d268cbSEd Tanous inline void handleLogServicesDumpClearLogComputerSystemPost( 305122d268cbSEd Tanous crow::App& app, const crow::Request& req, 305222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30537f3e84a1SEd Tanous const std::string& systemName) 305422d268cbSEd Tanous { 305522d268cbSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 305622d268cbSEd Tanous { 305722d268cbSEd Tanous return; 305822d268cbSEd Tanous } 30597f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 306022d268cbSEd Tanous { 30617f3e84a1SEd Tanous // Option currently returns no systems. TBD 30627f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30637f3e84a1SEd Tanous systemName); 30647f3e84a1SEd Tanous return; 30657f3e84a1SEd Tanous } 30667f3e84a1SEd Tanous if (systemName != "system") 30677f3e84a1SEd Tanous { 30687f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 30697f3e84a1SEd Tanous systemName); 307022d268cbSEd Tanous return; 307122d268cbSEd Tanous } 307222d268cbSEd Tanous clearDump(asyncResp, "System"); 307322d268cbSEd Tanous } 307422d268cbSEd Tanous 3075fdd26906SClaire Weinan inline void requestRoutesBMCDumpService(App& app) 3076fdd26906SClaire Weinan { 3077fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/") 3078fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3079fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3080fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "BMC")); 3081fdd26906SClaire Weinan } 3082fdd26906SClaire Weinan 3083fdd26906SClaire Weinan inline void requestRoutesBMCDumpEntryCollection(App& app) 3084fdd26906SClaire Weinan { 3085fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/") 3086fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3087fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3088fdd26906SClaire Weinan handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC")); 3089c9bb6861Sraviteja-b } 3090c9bb6861Sraviteja-b 30917e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app) 3092c9bb6861Sraviteja-b { 30937e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 30947e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3095ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 3096fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3097fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "BMC")); 3098fdd26906SClaire Weinan 30997e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 31007e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/") 3101ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 3102fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3103fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "BMC")); 3104c9bb6861Sraviteja-b } 3105c9bb6861Sraviteja-b 3106168d1b1aSCarson Labrado inline void requestRoutesBMCDumpEntryDownload(App& app) 3107168d1b1aSCarson Labrado { 3108168d1b1aSCarson Labrado BMCWEB_ROUTE( 3109168d1b1aSCarson Labrado app, 31109e9d99daSRavi Teja "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/") 3111168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3112168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3113168d1b1aSCarson Labrado handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC")); 3114168d1b1aSCarson Labrado } 3115168d1b1aSCarson Labrado 31167e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app) 3117c9bb6861Sraviteja-b { 31180fda0f12SGeorge Liu BMCWEB_ROUTE( 31190fda0f12SGeorge Liu app, 31200fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3121ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 31227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 3123fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost, 3124fdd26906SClaire Weinan std::ref(app), "BMC")); 3125a43be80fSAsmitha Karunanithi } 3126a43be80fSAsmitha Karunanithi 31277e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app) 312880319af1SAsmitha Karunanithi { 31290fda0f12SGeorge Liu BMCWEB_ROUTE( 31300fda0f12SGeorge Liu app, 31310fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/") 3132ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 3133fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3134fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "BMC")); 313545ca1b86SEd Tanous } 3136fdd26906SClaire Weinan 3137168d1b1aSCarson Labrado inline void requestRoutesDBusEventLogEntryDownload(App& app) 3138168d1b1aSCarson Labrado { 3139168d1b1aSCarson Labrado BMCWEB_ROUTE( 3140168d1b1aSCarson Labrado app, 31419e9d99daSRavi Teja "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/") 3142168d1b1aSCarson Labrado .privileges(redfish::privileges::getLogEntry) 3143168d1b1aSCarson Labrado .methods(boost::beast::http::verb::get)(std::bind_front( 3144168d1b1aSCarson Labrado handleDBusEventLogEntryDownloadGet, std::ref(app), "System")); 3145168d1b1aSCarson Labrado } 3146168d1b1aSCarson Labrado 3147fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpService(App& app) 3148fdd26906SClaire Weinan { 3149fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/") 3150fdd26906SClaire Weinan .privileges(redfish::privileges::getLogService) 3151fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3152fdd26906SClaire Weinan handleLogServicesDumpServiceGet, std::ref(app), "FaultLog")); 3153fdd26906SClaire Weinan } 3154fdd26906SClaire Weinan 3155fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntryCollection(App& app) 3156fdd26906SClaire Weinan { 3157fdd26906SClaire Weinan BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/") 3158fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntryCollection) 3159fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)( 3160fdd26906SClaire Weinan std::bind_front(handleLogServicesDumpEntriesCollectionGet, 3161fdd26906SClaire Weinan std::ref(app), "FaultLog")); 3162fdd26906SClaire Weinan } 3163fdd26906SClaire Weinan 3164fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpEntry(App& app) 3165fdd26906SClaire Weinan { 3166fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3167fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3168fdd26906SClaire Weinan .privileges(redfish::privileges::getLogEntry) 3169fdd26906SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 3170fdd26906SClaire Weinan handleLogServicesDumpEntryGet, std::ref(app), "FaultLog")); 3171fdd26906SClaire Weinan 3172fdd26906SClaire Weinan BMCWEB_ROUTE(app, 3173fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/") 3174fdd26906SClaire Weinan .privileges(redfish::privileges::deleteLogEntry) 3175fdd26906SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 3176fdd26906SClaire Weinan handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog")); 3177fdd26906SClaire Weinan } 3178fdd26906SClaire Weinan 3179fdd26906SClaire Weinan inline void requestRoutesFaultLogDumpClear(App& app) 3180fdd26906SClaire Weinan { 3181fdd26906SClaire Weinan BMCWEB_ROUTE( 3182fdd26906SClaire Weinan app, 3183fdd26906SClaire Weinan "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/") 3184fdd26906SClaire Weinan .privileges(redfish::privileges::postLogService) 3185fdd26906SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 3186fdd26906SClaire Weinan handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog")); 31875cb1dd27SAsmitha Karunanithi } 31885cb1dd27SAsmitha Karunanithi 31897e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app) 31905cb1dd27SAsmitha Karunanithi { 319122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/") 3192ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 31936ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 319422d268cbSEd Tanous handleLogServicesDumpServiceComputerSystemGet, std::ref(app))); 31955cb1dd27SAsmitha Karunanithi } 31965cb1dd27SAsmitha Karunanithi 31977e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app) 31987e860f15SJohn Edward Broadbent { 319922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/") 3200ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 320122d268cbSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 320222d268cbSEd Tanous handleLogServicesDumpEntriesCollectionComputerSystemGet, 320322d268cbSEd Tanous std::ref(app))); 32045cb1dd27SAsmitha Karunanithi } 32055cb1dd27SAsmitha Karunanithi 32067e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app) 32075cb1dd27SAsmitha Karunanithi { 32087e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 320922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3210ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 32116ab9ad54SClaire Weinan .methods(boost::beast::http::verb::get)(std::bind_front( 321222d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemGet, std::ref(app))); 32138d1b46d7Szhanghch05 32147e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 321522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/") 3216ed398213SEd Tanous .privileges(redfish::privileges::deleteLogEntry) 32176ab9ad54SClaire Weinan .methods(boost::beast::http::verb::delete_)(std::bind_front( 321822d268cbSEd Tanous handleLogServicesDumpEntryComputerSystemDelete, std::ref(app))); 32195cb1dd27SAsmitha Karunanithi } 3220c9bb6861Sraviteja-b 32217e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app) 3222c9bb6861Sraviteja-b { 32230fda0f12SGeorge Liu BMCWEB_ROUTE( 32240fda0f12SGeorge Liu app, 322522d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/") 3226ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 322722d268cbSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front( 322822d268cbSEd Tanous handleLogServicesDumpCollectDiagnosticDataComputerSystemPost, 322922d268cbSEd Tanous std::ref(app))); 3230a43be80fSAsmitha Karunanithi } 3231a43be80fSAsmitha Karunanithi 32327e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app) 3233a43be80fSAsmitha Karunanithi { 32340fda0f12SGeorge Liu BMCWEB_ROUTE( 32350fda0f12SGeorge Liu app, 323622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/") 3237ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 32386ab9ad54SClaire Weinan .methods(boost::beast::http::verb::post)(std::bind_front( 323922d268cbSEd Tanous handleLogServicesDumpClearLogComputerSystemPost, std::ref(app))); 3240013487e5Sraviteja-b } 3241013487e5Sraviteja-b 32427e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app) 32431da66f75SEd Tanous { 32443946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 32453946028dSAppaRao Puli // method for security reasons. 32461da66f75SEd Tanous /** 32471da66f75SEd Tanous * Functions triggers appropriate requests on DBus 32481da66f75SEd Tanous */ 324922d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/") 3250ed398213SEd Tanous // This is incorrect, should be: 3251ed398213SEd Tanous //.privileges(redfish::privileges::getLogService) 3252432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 3253002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3254002d39b4SEd Tanous [&app](const crow::Request& req, 325522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 325622d268cbSEd Tanous const std::string& systemName) { 32573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 325845ca1b86SEd Tanous { 325945ca1b86SEd Tanous return; 326045ca1b86SEd Tanous } 32617f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 32627f3e84a1SEd Tanous { 32637f3e84a1SEd Tanous // Option currently returns no systems. TBD 32647f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 32657f3e84a1SEd Tanous systemName); 32667f3e84a1SEd Tanous return; 32677f3e84a1SEd Tanous } 326822d268cbSEd Tanous if (systemName != "system") 326922d268cbSEd Tanous { 327022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 327122d268cbSEd Tanous systemName); 327222d268cbSEd Tanous return; 327322d268cbSEd Tanous } 327422d268cbSEd Tanous 32757e860f15SJohn Edward Broadbent // Copy over the static data to include the entries added by 32767e860f15SJohn Edward Broadbent // SubRoute 32770f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3278424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump"; 3279e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 32808e6c099aSJason M. Bills "#LogService.v1_2_0.LogService"; 32814f50ae4bSGunnar Mills asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service"; 32824f50ae4bSGunnar Mills asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service"; 328315b89725SV-Sanjana asyncResp->res.jsonValue["Id"] = "Crashdump"; 3284e1f26343SJason M. Bills asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 3285e1f26343SJason M. Bills asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3; 32867c8c4058STejas Patil 32877c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 32882b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 32897c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 32907c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 32917c8c4058STejas Patil redfishDateTimeOffset.second; 32927c8c4058STejas Patil 32931476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 3294ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3295002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] = 32961476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"; 3297002d39b4SEd Tanous asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"] 32981476687dSEd Tanous ["target"] = 32991476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"; 33007e860f15SJohn Edward Broadbent }); 33011da66f75SEd Tanous } 33021da66f75SEd Tanous 33037e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app) 33045b61b5e8SJason M. Bills { 33050fda0f12SGeorge Liu BMCWEB_ROUTE( 33060fda0f12SGeorge Liu app, 330722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/") 3308ed398213SEd Tanous // This is incorrect, should be: 3309ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3310432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 33117e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 331245ca1b86SEd Tanous [&app](const crow::Request& req, 331322d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 331422d268cbSEd Tanous const std::string& systemName) { 33153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 331645ca1b86SEd Tanous { 331745ca1b86SEd Tanous return; 331845ca1b86SEd Tanous } 33197f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 33207f3e84a1SEd Tanous { 33217f3e84a1SEd Tanous // Option currently returns no systems. TBD 33227f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33237f3e84a1SEd Tanous systemName); 33247f3e84a1SEd Tanous return; 33257f3e84a1SEd Tanous } 332622d268cbSEd Tanous if (systemName != "system") 332722d268cbSEd Tanous { 332822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 332922d268cbSEd Tanous systemName); 333022d268cbSEd Tanous return; 333122d268cbSEd Tanous } 33325b61b5e8SJason M. Bills crow::connections::systemBus->async_method_call( 33335e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3334cb13a392SEd Tanous const std::string&) { 33355b61b5e8SJason M. Bills if (ec) 33365b61b5e8SJason M. Bills { 33375b61b5e8SJason M. Bills messages::internalError(asyncResp->res); 33385b61b5e8SJason M. Bills return; 33395b61b5e8SJason M. Bills } 33405b61b5e8SJason M. Bills messages::success(asyncResp->res); 33415b61b5e8SJason M. Bills }, 3342002d39b4SEd Tanous crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll"); 33437e860f15SJohn Edward Broadbent }); 33445b61b5e8SJason M. Bills } 33455b61b5e8SJason M. Bills 33468d1b46d7Szhanghch05 static void 33478d1b46d7Szhanghch05 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 33488d1b46d7Szhanghch05 const std::string& logID, nlohmann::json& logEntryJson) 3349e855dd28SJason M. Bills { 3350043a0536SJohnathan Mantey auto getStoredLogCallback = 3351b9d36b47SEd Tanous [asyncResp, logID, 33525e7e2dc5SEd Tanous &logEntryJson](const boost::system::error_code& ec, 3353b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& params) { 3354e855dd28SJason M. Bills if (ec) 3355e855dd28SJason M. Bills { 335662598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 33571ddcf01aSJason M. Bills if (ec.value() == 33581ddcf01aSJason M. Bills boost::system::linux_error::bad_request_descriptor) 33591ddcf01aSJason M. Bills { 3360002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 33611ddcf01aSJason M. Bills } 33621ddcf01aSJason M. Bills else 33631ddcf01aSJason M. Bills { 3364e855dd28SJason M. Bills messages::internalError(asyncResp->res); 33651ddcf01aSJason M. Bills } 3366e855dd28SJason M. Bills return; 3367e855dd28SJason M. Bills } 3368043a0536SJohnathan Mantey 3369043a0536SJohnathan Mantey std::string timestamp{}; 3370043a0536SJohnathan Mantey std::string filename{}; 3371043a0536SJohnathan Mantey std::string logfile{}; 33722c70f800SEd Tanous parseCrashdumpParameters(params, filename, timestamp, logfile); 3373043a0536SJohnathan Mantey 3374043a0536SJohnathan Mantey if (filename.empty() || timestamp.empty()) 3375e855dd28SJason M. Bills { 33769db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3377e855dd28SJason M. Bills return; 3378e855dd28SJason M. Bills } 3379e855dd28SJason M. Bills 3380043a0536SJohnathan Mantey std::string crashdumpURI = 3381e855dd28SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + 3382043a0536SJohnathan Mantey logID + "/" + filename; 338384afc48bSJason M. Bills nlohmann::json::object_t logEntry; 33849c11a172SVijay Lobo logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 3385ef4c65b7SEd Tanous logEntry["@odata.id"] = boost::urls::format( 3386ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}", 3387ef4c65b7SEd Tanous logID); 338884afc48bSJason M. Bills logEntry["Name"] = "CPU Crashdump"; 338984afc48bSJason M. Bills logEntry["Id"] = logID; 339084afc48bSJason M. Bills logEntry["EntryType"] = "Oem"; 339184afc48bSJason M. Bills logEntry["AdditionalDataURI"] = std::move(crashdumpURI); 339284afc48bSJason M. Bills logEntry["DiagnosticDataType"] = "OEM"; 339384afc48bSJason M. Bills logEntry["OEMDiagnosticDataType"] = "PECICrashdump"; 339484afc48bSJason M. Bills logEntry["Created"] = std::move(timestamp); 33952b20ef6eSJason M. Bills 33962b20ef6eSJason M. Bills // If logEntryJson references an array of LogEntry resources 33972b20ef6eSJason M. Bills // ('Members' list), then push this as a new entry, otherwise set it 33982b20ef6eSJason M. Bills // directly 33992b20ef6eSJason M. Bills if (logEntryJson.is_array()) 34002b20ef6eSJason M. Bills { 34012b20ef6eSJason M. Bills logEntryJson.push_back(logEntry); 34022b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members@odata.count"] = 34032b20ef6eSJason M. Bills logEntryJson.size(); 34042b20ef6eSJason M. Bills } 34052b20ef6eSJason M. Bills else 34062b20ef6eSJason M. Bills { 3407d405bb51SJason M. Bills logEntryJson.update(logEntry); 34082b20ef6eSJason M. Bills } 3409e855dd28SJason M. Bills }; 3410d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3411d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3412d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3413d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 3414e855dd28SJason M. Bills } 3415e855dd28SJason M. Bills 34167e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app) 34171da66f75SEd Tanous { 34183946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34193946028dSAppaRao Puli // method for security reasons. 34201da66f75SEd Tanous /** 34211da66f75SEd Tanous * Functions triggers appropriate requests on DBus 34221da66f75SEd Tanous */ 34237e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 342422d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") 3425ed398213SEd Tanous // This is incorrect, should be. 3426ed398213SEd Tanous //.privileges(redfish::privileges::postLogEntryCollection) 3427432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3428002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3429002d39b4SEd Tanous [&app](const crow::Request& req, 343022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 343122d268cbSEd Tanous const std::string& systemName) { 34323ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 343345ca1b86SEd Tanous { 343445ca1b86SEd Tanous return; 343545ca1b86SEd Tanous } 34367f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 34377f3e84a1SEd Tanous { 34387f3e84a1SEd Tanous // Option currently returns no systems. TBD 34397f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 34407f3e84a1SEd Tanous systemName); 34417f3e84a1SEd Tanous return; 34427f3e84a1SEd Tanous } 344322d268cbSEd Tanous if (systemName != "system") 344422d268cbSEd Tanous { 344522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 344622d268cbSEd Tanous systemName); 344722d268cbSEd Tanous return; 344822d268cbSEd Tanous } 344922d268cbSEd Tanous 34507a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 34517a1dbc48SGeorge Liu crashdumpInterface}; 34527a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 34537a1dbc48SGeorge Liu "/", 0, interfaces, 34547a1dbc48SGeorge Liu [asyncResp](const boost::system::error_code& ec, 34552b20ef6eSJason M. Bills const std::vector<std::string>& resp) { 34561da66f75SEd Tanous if (ec) 34571da66f75SEd Tanous { 34581da66f75SEd Tanous if (ec.value() != 34591da66f75SEd Tanous boost::system::errc::no_such_file_or_directory) 34601da66f75SEd Tanous { 346162598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get entries ec: {}", 346262598e31SEd Tanous ec.message()); 3463f12894f8SJason M. Bills messages::internalError(asyncResp->res); 34641da66f75SEd Tanous return; 34651da66f75SEd Tanous } 34661da66f75SEd Tanous } 3467e1f26343SJason M. Bills asyncResp->res.jsonValue["@odata.type"] = 34681da66f75SEd Tanous "#LogEntryCollection.LogEntryCollection"; 34690f74e643SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 3470424c4176SJason M. Bills "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"; 3471002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries"; 3472e1f26343SJason M. Bills asyncResp->res.jsonValue["Description"] = 3473424c4176SJason M. Bills "Collection of Crashdump Entries"; 3474002d39b4SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 3475a2dd60a6SBrandon Kim asyncResp->res.jsonValue["Members@odata.count"] = 0; 34762b20ef6eSJason M. Bills 34772b20ef6eSJason M. Bills for (const std::string& path : resp) 34781da66f75SEd Tanous { 34792b20ef6eSJason M. Bills const sdbusplus::message::object_path objPath(path); 3480e855dd28SJason M. Bills // Get the log ID 34812b20ef6eSJason M. Bills std::string logID = objPath.filename(); 34822b20ef6eSJason M. Bills if (logID.empty()) 34831da66f75SEd Tanous { 3484e855dd28SJason M. Bills continue; 34851da66f75SEd Tanous } 3486e855dd28SJason M. Bills // Add the log entry to the array 34872b20ef6eSJason M. Bills logCrashdumpEntry(asyncResp, logID, 34882b20ef6eSJason M. Bills asyncResp->res.jsonValue["Members"]); 34891da66f75SEd Tanous } 34907a1dbc48SGeorge Liu }); 34917e860f15SJohn Edward Broadbent }); 34921da66f75SEd Tanous } 34931da66f75SEd Tanous 34947e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app) 34951da66f75SEd Tanous { 34963946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 34973946028dSAppaRao Puli // method for security reasons. 34981da66f75SEd Tanous 34997e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 350022d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/") 3501ed398213SEd Tanous // this is incorrect, should be 3502ed398213SEd Tanous // .privileges(redfish::privileges::getLogEntry) 3503432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 35047e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 350545ca1b86SEd Tanous [&app](const crow::Request& req, 35067e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350722d268cbSEd Tanous const std::string& systemName, const std::string& param) { 35083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 350945ca1b86SEd Tanous { 351045ca1b86SEd Tanous return; 351145ca1b86SEd Tanous } 35127f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35137f3e84a1SEd Tanous { 35147f3e84a1SEd Tanous // Option currently returns no systems. TBD 35157f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35167f3e84a1SEd Tanous systemName); 35177f3e84a1SEd Tanous return; 35187f3e84a1SEd Tanous } 351922d268cbSEd Tanous if (systemName != "system") 352022d268cbSEd Tanous { 352122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 352222d268cbSEd Tanous systemName); 352322d268cbSEd Tanous return; 352422d268cbSEd Tanous } 35257e860f15SJohn Edward Broadbent const std::string& logID = param; 3526e855dd28SJason M. Bills logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue); 35277e860f15SJohn Edward Broadbent }); 3528e855dd28SJason M. Bills } 3529e855dd28SJason M. Bills 35307e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app) 3531e855dd28SJason M. Bills { 35323946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 35333946028dSAppaRao Puli // method for security reasons. 35347e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 35357e860f15SJohn Edward Broadbent app, 353622d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/") 3537ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 35387e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3539a4ce114aSNan Zhou [](const crow::Request& req, 35407e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 354122d268cbSEd Tanous const std::string& systemName, const std::string& logID, 354222d268cbSEd Tanous const std::string& fileName) { 35432a9beeedSShounak Mitra // Do not call getRedfishRoute here since the crashdump file is not a 35442a9beeedSShounak Mitra // Redfish resource. 354522d268cbSEd Tanous 35467f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 35477f3e84a1SEd Tanous { 35487f3e84a1SEd Tanous // Option currently returns no systems. TBD 35497f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 35507f3e84a1SEd Tanous systemName); 35517f3e84a1SEd Tanous return; 35527f3e84a1SEd Tanous } 355322d268cbSEd Tanous if (systemName != "system") 355422d268cbSEd Tanous { 355522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 355622d268cbSEd Tanous systemName); 355722d268cbSEd Tanous return; 355822d268cbSEd Tanous } 355922d268cbSEd Tanous 3560043a0536SJohnathan Mantey auto getStoredLogCallback = 356139662a3bSEd Tanous [asyncResp, logID, fileName, url(boost::urls::url(req.url()))]( 35625e7e2dc5SEd Tanous const boost::system::error_code& ec, 3563002d39b4SEd Tanous const std::vector< 3564002d39b4SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 35657e860f15SJohn Edward Broadbent resp) { 35661da66f75SEd Tanous if (ec) 35671da66f75SEd Tanous { 356862598e31SEd Tanous BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message()); 3569f12894f8SJason M. Bills messages::internalError(asyncResp->res); 35701da66f75SEd Tanous return; 35711da66f75SEd Tanous } 3572e855dd28SJason M. Bills 3573043a0536SJohnathan Mantey std::string dbusFilename{}; 3574043a0536SJohnathan Mantey std::string dbusTimestamp{}; 3575043a0536SJohnathan Mantey std::string dbusFilepath{}; 3576043a0536SJohnathan Mantey 3577002d39b4SEd Tanous parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp, 3578002d39b4SEd Tanous dbusFilepath); 3579043a0536SJohnathan Mantey 3580043a0536SJohnathan Mantey if (dbusFilename.empty() || dbusTimestamp.empty() || 3581043a0536SJohnathan Mantey dbusFilepath.empty()) 35821da66f75SEd Tanous { 35839db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 35841da66f75SEd Tanous return; 35851da66f75SEd Tanous } 3586e855dd28SJason M. Bills 3587043a0536SJohnathan Mantey // Verify the file name parameter is correct 3588043a0536SJohnathan Mantey if (fileName != dbusFilename) 3589043a0536SJohnathan Mantey { 35909db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3591043a0536SJohnathan Mantey return; 3592043a0536SJohnathan Mantey } 3593043a0536SJohnathan Mantey 359427b0cf90SEd Tanous if (!asyncResp->res.openFile(dbusFilepath)) 3595043a0536SJohnathan Mantey { 35969db4ba25SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "LogEntry", logID); 3597043a0536SJohnathan Mantey return; 3598043a0536SJohnathan Mantey } 3599043a0536SJohnathan Mantey 36007e860f15SJohn Edward Broadbent // Configure this to be a file download when accessed 36017e860f15SJohn Edward Broadbent // from a browser 3602d9f6c621SEd Tanous asyncResp->res.addHeader( 3603d9f6c621SEd Tanous boost::beast::http::field::content_disposition, "attachment"); 36041da66f75SEd Tanous }; 3605d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3606d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, crashdumpObject, 3607d1bde9e5SKrzysztof Grobelny crashdumpPath + std::string("/") + logID, crashdumpInterface, 3608d1bde9e5SKrzysztof Grobelny std::move(getStoredLogCallback)); 36097e860f15SJohn Edward Broadbent }); 36101da66f75SEd Tanous } 36111da66f75SEd Tanous 3612c5a4c82aSJason M. Bills enum class OEMDiagnosticType 3613c5a4c82aSJason M. Bills { 3614c5a4c82aSJason M. Bills onDemand, 3615c5a4c82aSJason M. Bills telemetry, 3616c5a4c82aSJason M. Bills invalid, 3617c5a4c82aSJason M. Bills }; 3618c5a4c82aSJason M. Bills 361926ccae32SEd Tanous inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr) 3620c5a4c82aSJason M. Bills { 3621c5a4c82aSJason M. Bills if (oemDiagStr == "OnDemand") 3622c5a4c82aSJason M. Bills { 3623c5a4c82aSJason M. Bills return OEMDiagnosticType::onDemand; 3624c5a4c82aSJason M. Bills } 3625c5a4c82aSJason M. Bills if (oemDiagStr == "Telemetry") 3626c5a4c82aSJason M. Bills { 3627c5a4c82aSJason M. Bills return OEMDiagnosticType::telemetry; 3628c5a4c82aSJason M. Bills } 3629c5a4c82aSJason M. Bills 3630c5a4c82aSJason M. Bills return OEMDiagnosticType::invalid; 3631c5a4c82aSJason M. Bills } 3632c5a4c82aSJason M. Bills 36337e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app) 36341da66f75SEd Tanous { 36353946028dSAppaRao Puli // Note: Deviated from redfish privilege registry for GET & HEAD 36363946028dSAppaRao Puli // method for security reasons. 36370fda0f12SGeorge Liu BMCWEB_ROUTE( 36380fda0f12SGeorge Liu app, 363922d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/") 3640ed398213SEd Tanous // The below is incorrect; Should be ConfigureManager 3641ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3642432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 3643002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 3644002d39b4SEd Tanous [&app](const crow::Request& req, 364522d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 364622d268cbSEd Tanous const std::string& systemName) { 36473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 364845ca1b86SEd Tanous { 364945ca1b86SEd Tanous return; 365045ca1b86SEd Tanous } 365122d268cbSEd Tanous 36527f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 36537f3e84a1SEd Tanous { 36547f3e84a1SEd Tanous // Option currently returns no systems. TBD 36557f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 36567f3e84a1SEd Tanous systemName); 36577f3e84a1SEd Tanous return; 36587f3e84a1SEd Tanous } 365922d268cbSEd Tanous if (systemName != "system") 366022d268cbSEd Tanous { 366122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 366222d268cbSEd Tanous systemName); 366322d268cbSEd Tanous return; 366422d268cbSEd Tanous } 366522d268cbSEd Tanous 36668e6c099aSJason M. Bills std::string diagnosticDataType; 36678e6c099aSJason M. Bills std::string oemDiagnosticDataType; 366815ed6780SWilly Tu if (!redfish::json_util::readJsonAction( 3669002d39b4SEd Tanous req, asyncResp->res, "DiagnosticDataType", diagnosticDataType, 3670002d39b4SEd Tanous "OEMDiagnosticDataType", oemDiagnosticDataType)) 36718e6c099aSJason M. Bills { 36728e6c099aSJason M. Bills return; 36738e6c099aSJason M. Bills } 36748e6c099aSJason M. Bills 36758e6c099aSJason M. Bills if (diagnosticDataType != "OEM") 36768e6c099aSJason M. Bills { 367762598e31SEd Tanous BMCWEB_LOG_ERROR( 367862598e31SEd Tanous "Only OEM DiagnosticDataType supported for Crashdump"); 36798e6c099aSJason M. Bills messages::actionParameterValueFormatError( 36808e6c099aSJason M. Bills asyncResp->res, diagnosticDataType, "DiagnosticDataType", 36818e6c099aSJason M. Bills "CollectDiagnosticData"); 36828e6c099aSJason M. Bills return; 36838e6c099aSJason M. Bills } 36848e6c099aSJason M. Bills 3685c5a4c82aSJason M. Bills OEMDiagnosticType oemDiagType = 3686c5a4c82aSJason M. Bills getOEMDiagnosticType(oemDiagnosticDataType); 3687c5a4c82aSJason M. Bills 3688c5a4c82aSJason M. Bills std::string iface; 3689c5a4c82aSJason M. Bills std::string method; 3690c5a4c82aSJason M. Bills std::string taskMatchStr; 3691c5a4c82aSJason M. Bills if (oemDiagType == OEMDiagnosticType::onDemand) 3692c5a4c82aSJason M. Bills { 3693c5a4c82aSJason M. Bills iface = crashdumpOnDemandInterface; 3694c5a4c82aSJason M. Bills method = "GenerateOnDemandLog"; 3695c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3696c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3697c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3698c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3699c5a4c82aSJason M. Bills } 3700c5a4c82aSJason M. Bills else if (oemDiagType == OEMDiagnosticType::telemetry) 3701c5a4c82aSJason M. Bills { 3702c5a4c82aSJason M. Bills iface = crashdumpTelemetryInterface; 3703c5a4c82aSJason M. Bills method = "GenerateTelemetryLog"; 3704c5a4c82aSJason M. Bills taskMatchStr = "type='signal'," 3705c5a4c82aSJason M. Bills "interface='org.freedesktop.DBus.Properties'," 3706c5a4c82aSJason M. Bills "member='PropertiesChanged'," 3707c5a4c82aSJason M. Bills "arg0namespace='com.intel.crashdump'"; 3708c5a4c82aSJason M. Bills } 3709c5a4c82aSJason M. Bills else 3710c5a4c82aSJason M. Bills { 371162598e31SEd Tanous BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}", 371262598e31SEd Tanous oemDiagnosticDataType); 3713c5a4c82aSJason M. Bills messages::actionParameterValueFormatError( 3714002d39b4SEd Tanous asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType", 3715002d39b4SEd Tanous "CollectDiagnosticData"); 3716c5a4c82aSJason M. Bills return; 3717c5a4c82aSJason M. Bills } 3718c5a4c82aSJason M. Bills 3719c5a4c82aSJason M. Bills auto collectCrashdumpCallback = 3720c5a4c82aSJason M. Bills [asyncResp, payload(task::Payload(req)), 37215e7e2dc5SEd Tanous taskMatchStr](const boost::system::error_code& ec, 372298be3e39SEd Tanous const std::string&) mutable { 37231da66f75SEd Tanous if (ec) 37241da66f75SEd Tanous { 3725002d39b4SEd Tanous if (ec.value() == boost::system::errc::operation_not_supported) 37261da66f75SEd Tanous { 3727f12894f8SJason M. Bills messages::resourceInStandby(asyncResp->res); 37281da66f75SEd Tanous } 37294363d3b2SJason M. Bills else if (ec.value() == 37304363d3b2SJason M. Bills boost::system::errc::device_or_resource_busy) 37314363d3b2SJason M. Bills { 3732002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 3733002d39b4SEd Tanous "60"); 37344363d3b2SJason M. Bills } 37351da66f75SEd Tanous else 37361da66f75SEd Tanous { 3737f12894f8SJason M. Bills messages::internalError(asyncResp->res); 37381da66f75SEd Tanous } 37391da66f75SEd Tanous return; 37401da66f75SEd Tanous } 3741002d39b4SEd Tanous std::shared_ptr<task::TaskData> task = task::TaskData::createTask( 37428b24275dSEd Tanous [](const boost::system::error_code& ec2, sdbusplus::message_t&, 3743002d39b4SEd Tanous const std::shared_ptr<task::TaskData>& taskData) { 37448b24275dSEd Tanous if (!ec2) 374566afe4faSJames Feist { 3746002d39b4SEd Tanous taskData->messages.emplace_back(messages::taskCompletedOK( 3747e5d5006bSJames Feist std::to_string(taskData->index))); 3748831d6b09SJames Feist taskData->state = "Completed"; 374966afe4faSJames Feist } 375032898ceaSJames Feist return task::completed; 375166afe4faSJames Feist }, 3752c5a4c82aSJason M. Bills taskMatchStr); 3753c5a4c82aSJason M. Bills 375446229577SJames Feist task->startTimer(std::chrono::minutes(5)); 375546229577SJames Feist task->populateResp(asyncResp->res); 375698be3e39SEd Tanous task->payload.emplace(std::move(payload)); 37571da66f75SEd Tanous }; 37588e6c099aSJason M. Bills 37591da66f75SEd Tanous crow::connections::systemBus->async_method_call( 3760002d39b4SEd Tanous std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath, 3761002d39b4SEd Tanous iface, method); 37627e860f15SJohn Edward Broadbent }); 37636eda7685SKenny L. Ku } 37646eda7685SKenny L. Ku 3765cb92c03bSAndrew Geissler /** 3766cb92c03bSAndrew Geissler * DBusLogServiceActionsClear class supports POST method for ClearLog action. 3767cb92c03bSAndrew Geissler */ 37687e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app) 3769cb92c03bSAndrew Geissler { 3770cb92c03bSAndrew Geissler /** 3771cb92c03bSAndrew Geissler * Function handles POST method request. 3772cb92c03bSAndrew Geissler * The Clear Log actions does not require any parameter.The action deletes 3773cb92c03bSAndrew Geissler * all entries found in the Entries collection for this Log Service. 3774cb92c03bSAndrew Geissler */ 37757e860f15SJohn Edward Broadbent 37760fda0f12SGeorge Liu BMCWEB_ROUTE( 37770fda0f12SGeorge Liu app, 377822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/") 3779ed398213SEd Tanous .privileges(redfish::privileges::postLogService) 37807e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 378145ca1b86SEd Tanous [&app](const crow::Request& req, 378222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 378322d268cbSEd Tanous const std::string& systemName) { 37843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 378545ca1b86SEd Tanous { 378645ca1b86SEd Tanous return; 378745ca1b86SEd Tanous } 37887f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 37897f3e84a1SEd Tanous { 37907f3e84a1SEd Tanous // Option currently returns no systems. TBD 37917f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 37927f3e84a1SEd Tanous systemName); 37937f3e84a1SEd Tanous return; 37947f3e84a1SEd Tanous } 379522d268cbSEd Tanous if (systemName != "system") 379622d268cbSEd Tanous { 379722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 379822d268cbSEd Tanous systemName); 379922d268cbSEd Tanous return; 380022d268cbSEd Tanous } 380162598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all entries."); 3802cb92c03bSAndrew Geissler 3803cb92c03bSAndrew Geissler // Process response from Logging service. 38045e7e2dc5SEd Tanous auto respHandler = [asyncResp](const boost::system::error_code& ec) { 380562598e31SEd Tanous BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done"); 3806cb92c03bSAndrew Geissler if (ec) 3807cb92c03bSAndrew Geissler { 3808cb92c03bSAndrew Geissler // TODO Handle for specific error code 380962598e31SEd Tanous BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec); 3810cb92c03bSAndrew Geissler asyncResp->res.result( 3811cb92c03bSAndrew Geissler boost::beast::http::status::internal_server_error); 3812cb92c03bSAndrew Geissler return; 3813cb92c03bSAndrew Geissler } 3814cb92c03bSAndrew Geissler 3815002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 3816cb92c03bSAndrew Geissler }; 3817cb92c03bSAndrew Geissler 3818cb92c03bSAndrew Geissler // Make call to Logging service to request Clear Log 3819cb92c03bSAndrew Geissler crow::connections::systemBus->async_method_call( 38202c70f800SEd Tanous respHandler, "xyz.openbmc_project.Logging", 3821cb92c03bSAndrew Geissler "/xyz/openbmc_project/logging", 3822cb92c03bSAndrew Geissler "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 38237e860f15SJohn Edward Broadbent }); 3824cb92c03bSAndrew Geissler } 3825a3316fc6SZhikuiRen 3826a3316fc6SZhikuiRen /**************************************************** 3827a3316fc6SZhikuiRen * Redfish PostCode interfaces 3828a3316fc6SZhikuiRen * using DBUS interface: getPostCodesTS 3829a3316fc6SZhikuiRen ******************************************************/ 38307e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app) 3831a3316fc6SZhikuiRen { 383222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/") 3833ed398213SEd Tanous .privileges(redfish::privileges::getLogService) 3834002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3835002d39b4SEd Tanous [&app](const crow::Request& req, 383622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 383722d268cbSEd Tanous const std::string& systemName) { 38383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 383945ca1b86SEd Tanous { 384045ca1b86SEd Tanous return; 384145ca1b86SEd Tanous } 38427f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38437f3e84a1SEd Tanous { 38447f3e84a1SEd Tanous // Option currently returns no systems. TBD 38457f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38467f3e84a1SEd Tanous systemName); 38477f3e84a1SEd Tanous return; 38487f3e84a1SEd Tanous } 384922d268cbSEd Tanous if (systemName != "system") 385022d268cbSEd Tanous { 385122d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 385222d268cbSEd Tanous systemName); 385322d268cbSEd Tanous return; 385422d268cbSEd Tanous } 38551476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 38561476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes"; 38571476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3858b25644a1SJanet Adkins "#LogService.v1_2_0.LogService"; 38591476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service"; 38601476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service"; 3861ed34a4adSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes"; 38621476687dSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; 38631476687dSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] = 38641476687dSEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 38657c8c4058STejas Patil 38667c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 38672b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 38680fda0f12SGeorge Liu asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 38697c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 38707c8c4058STejas Patil redfishDateTimeOffset.second; 38717c8c4058STejas Patil 3872a3316fc6SZhikuiRen asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { 38737e860f15SJohn Edward Broadbent {"target", 38740fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}}; 38757e860f15SJohn Edward Broadbent }); 3876a3316fc6SZhikuiRen } 3877a3316fc6SZhikuiRen 38787e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app) 3879a3316fc6SZhikuiRen { 38800fda0f12SGeorge Liu BMCWEB_ROUTE( 38810fda0f12SGeorge Liu app, 388222d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/") 3883ed398213SEd Tanous // The following privilege is incorrect; It should be ConfigureManager 3884ed398213SEd Tanous //.privileges(redfish::privileges::postLogService) 3885432a890cSEd Tanous .privileges({{"ConfigureComponents"}}) 38867e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 388745ca1b86SEd Tanous [&app](const crow::Request& req, 388822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 388922d268cbSEd Tanous const std::string& systemName) { 38903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 389145ca1b86SEd Tanous { 389245ca1b86SEd Tanous return; 389345ca1b86SEd Tanous } 38947f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 38957f3e84a1SEd Tanous { 38967f3e84a1SEd Tanous // Option currently returns no systems. TBD 38977f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 38987f3e84a1SEd Tanous systemName); 38997f3e84a1SEd Tanous return; 39007f3e84a1SEd Tanous } 390122d268cbSEd Tanous if (systemName != "system") 390222d268cbSEd Tanous { 390322d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 390422d268cbSEd Tanous systemName); 390522d268cbSEd Tanous return; 390622d268cbSEd Tanous } 390762598e31SEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries."); 3908a3316fc6SZhikuiRen 3909a3316fc6SZhikuiRen // Make call to post-code service to request clear all 3910a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 39115e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 3912a3316fc6SZhikuiRen if (ec) 3913a3316fc6SZhikuiRen { 3914a3316fc6SZhikuiRen // TODO Handle for specific error code 391562598e31SEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}", 391662598e31SEd Tanous ec); 3917002d39b4SEd Tanous asyncResp->res.result( 3918002d39b4SEd Tanous boost::beast::http::status::internal_server_error); 3919a3316fc6SZhikuiRen messages::internalError(asyncResp->res); 3920a3316fc6SZhikuiRen return; 3921a3316fc6SZhikuiRen } 392218fc70c0STony Lee messages::success(asyncResp->res); 3923a3316fc6SZhikuiRen }, 392415124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 392515124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 3926a3316fc6SZhikuiRen "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll"); 39277e860f15SJohn Edward Broadbent }); 3928a3316fc6SZhikuiRen } 3929a3316fc6SZhikuiRen 39306f284d24SJiaqing Zhao /** 39316f284d24SJiaqing Zhao * @brief Parse post code ID and get the current value and index value 39326f284d24SJiaqing Zhao * eg: postCodeID=B1-2, currentValue=1, index=2 39336f284d24SJiaqing Zhao * 39346f284d24SJiaqing Zhao * @param[in] postCodeID Post Code ID 39356f284d24SJiaqing Zhao * @param[out] currentValue Current value 39366f284d24SJiaqing Zhao * @param[out] index Index value 39376f284d24SJiaqing Zhao * 39386f284d24SJiaqing Zhao * @return bool true if the parsing is successful, false the parsing fails 39396f284d24SJiaqing Zhao */ 39406f284d24SJiaqing Zhao inline static bool parsePostCode(const std::string& postCodeID, 39416f284d24SJiaqing Zhao uint64_t& currentValue, uint16_t& index) 39426f284d24SJiaqing Zhao { 39436f284d24SJiaqing Zhao std::vector<std::string> split; 394450ebd4afSEd Tanous bmcweb::split(split, postCodeID, '-'); 39456f284d24SJiaqing Zhao if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B') 39466f284d24SJiaqing Zhao { 39476f284d24SJiaqing Zhao return false; 39486f284d24SJiaqing Zhao } 39496f284d24SJiaqing Zhao 395084396af9SPatrick Williams auto start = std::next(split[0].begin()); 395184396af9SPatrick Williams auto end = split[0].end(); 395284396af9SPatrick Williams auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index); 39536f284d24SJiaqing Zhao 395484396af9SPatrick Williams if (ptrIndex != &*end || ecIndex != std::errc()) 39556f284d24SJiaqing Zhao { 39566f284d24SJiaqing Zhao return false; 39576f284d24SJiaqing Zhao } 39586f284d24SJiaqing Zhao 395984396af9SPatrick Williams start = split[1].begin(); 396084396af9SPatrick Williams end = split[1].end(); 39616f284d24SJiaqing Zhao 396284396af9SPatrick Williams auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue); 39636f284d24SJiaqing Zhao 396484396af9SPatrick Williams return ptrValue == &*end && ecValue == std::errc(); 39656f284d24SJiaqing Zhao } 39666f284d24SJiaqing Zhao 39676f284d24SJiaqing Zhao static bool fillPostCodeEntry( 3968ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 39696c9a279eSManojkiran Eda const boost::container::flat_map< 39706c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode, 3971a3316fc6SZhikuiRen const uint16_t bootIndex, const uint64_t codeIndex = 0, 3972a3316fc6SZhikuiRen const uint64_t skip = 0, const uint64_t top = 0) 3973a3316fc6SZhikuiRen { 3974a3316fc6SZhikuiRen // Get the Message from the MessageRegistry 3975fffb8c1fSEd Tanous const registries::Message* message = 3976fffb8c1fSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode"); 3977a3316fc6SZhikuiRen 3978a3316fc6SZhikuiRen uint64_t currentCodeIndex = 0; 3979a3316fc6SZhikuiRen uint64_t firstCodeTimeUs = 0; 39806c9a279eSManojkiran Eda for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 39816c9a279eSManojkiran Eda code : postcode) 3982a3316fc6SZhikuiRen { 3983a3316fc6SZhikuiRen currentCodeIndex++; 3984a3316fc6SZhikuiRen std::string postcodeEntryID = 3985a3316fc6SZhikuiRen "B" + std::to_string(bootIndex) + "-" + 3986a3316fc6SZhikuiRen std::to_string(currentCodeIndex); // 1 based index in EntryID string 3987a3316fc6SZhikuiRen 3988a3316fc6SZhikuiRen uint64_t usecSinceEpoch = code.first; 3989a3316fc6SZhikuiRen uint64_t usTimeOffset = 0; 3990a3316fc6SZhikuiRen 3991a3316fc6SZhikuiRen if (1 == currentCodeIndex) 3992a3316fc6SZhikuiRen { // already incremented 3993a3316fc6SZhikuiRen firstCodeTimeUs = code.first; 3994a3316fc6SZhikuiRen } 3995a3316fc6SZhikuiRen else 3996a3316fc6SZhikuiRen { 3997a3316fc6SZhikuiRen usTimeOffset = code.first - firstCodeTimeUs; 3998a3316fc6SZhikuiRen } 3999a3316fc6SZhikuiRen 4000a3316fc6SZhikuiRen // skip if no specific codeIndex is specified and currentCodeIndex does 4001a3316fc6SZhikuiRen // not fall between top and skip 4002a3316fc6SZhikuiRen if ((codeIndex == 0) && 4003a3316fc6SZhikuiRen (currentCodeIndex <= skip || currentCodeIndex > top)) 4004a3316fc6SZhikuiRen { 4005a3316fc6SZhikuiRen continue; 4006a3316fc6SZhikuiRen } 4007a3316fc6SZhikuiRen 40084e0453b1SGunnar Mills // skip if a specific codeIndex is specified and does not match the 4009a3316fc6SZhikuiRen // currentIndex 4010a3316fc6SZhikuiRen if ((codeIndex > 0) && (currentCodeIndex != codeIndex)) 4011a3316fc6SZhikuiRen { 4012a3316fc6SZhikuiRen // This is done for simplicity. 1st entry is needed to calculate 4013a3316fc6SZhikuiRen // time offset. To improve efficiency, one can get to the entry 4014a3316fc6SZhikuiRen // directly (possibly with flatmap's nth method) 4015a3316fc6SZhikuiRen continue; 4016a3316fc6SZhikuiRen } 4017a3316fc6SZhikuiRen 4018a3316fc6SZhikuiRen // currentCodeIndex is within top and skip or equal to specified code 4019a3316fc6SZhikuiRen // index 4020a3316fc6SZhikuiRen 4021a3316fc6SZhikuiRen // Get the Created time from the timestamp 4022a3316fc6SZhikuiRen std::string entryTimeStr; 40232a025611SKonstantin Aladyshev entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch); 4024a3316fc6SZhikuiRen 4025a3316fc6SZhikuiRen // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex) 4026a3316fc6SZhikuiRen std::ostringstream hexCode; 4027a3316fc6SZhikuiRen hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex 40286c9a279eSManojkiran Eda << std::get<0>(code.second); 4029a3316fc6SZhikuiRen std::ostringstream timeOffsetStr; 4030a3316fc6SZhikuiRen // Set Fixed -Point Notation 4031a3316fc6SZhikuiRen timeOffsetStr << std::fixed; 4032a3316fc6SZhikuiRen // Set precision to 4 digits 4033a3316fc6SZhikuiRen timeOffsetStr << std::setprecision(4); 4034a3316fc6SZhikuiRen // Add double to stream 4035a3316fc6SZhikuiRen timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000; 4036a3316fc6SZhikuiRen 40371e6deaf6SEd Tanous std::string bootIndexStr = std::to_string(bootIndex); 40381e6deaf6SEd Tanous std::string timeOffsetString = timeOffsetStr.str(); 40391e6deaf6SEd Tanous std::string hexCodeStr = hexCode.str(); 4040a3316fc6SZhikuiRen 40411e6deaf6SEd Tanous std::array<std::string_view, 3> messageArgs = { 40421e6deaf6SEd Tanous bootIndexStr, timeOffsetString, hexCodeStr}; 40431e6deaf6SEd Tanous 40441e6deaf6SEd Tanous std::string msg = 40451e6deaf6SEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message); 40461e6deaf6SEd Tanous if (msg.empty()) 4047a3316fc6SZhikuiRen { 40481e6deaf6SEd Tanous messages::internalError(asyncResp->res); 40491e6deaf6SEd Tanous return false; 4050a3316fc6SZhikuiRen } 4051a3316fc6SZhikuiRen 4052d4342a92STim Lee // Get Severity template from message registry 4053d4342a92STim Lee std::string severity; 4054d4342a92STim Lee if (message != nullptr) 4055d4342a92STim Lee { 40565f2b84eeSEd Tanous severity = message->messageSeverity; 4057d4342a92STim Lee } 4058d4342a92STim Lee 40596f284d24SJiaqing Zhao // Format entry 40606f284d24SJiaqing Zhao nlohmann::json::object_t bmcLogEntry; 40619c11a172SVijay Lobo bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 4062ef4c65b7SEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format( 4063ef4c65b7SEd Tanous "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}", 4064ef4c65b7SEd Tanous postcodeEntryID); 406584afc48bSJason M. Bills bmcLogEntry["Name"] = "POST Code Log Entry"; 406684afc48bSJason M. Bills bmcLogEntry["Id"] = postcodeEntryID; 406784afc48bSJason M. Bills bmcLogEntry["Message"] = std::move(msg); 406884afc48bSJason M. Bills bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode"; 40691e6deaf6SEd Tanous bmcLogEntry["MessageArgs"] = messageArgs; 407084afc48bSJason M. Bills bmcLogEntry["EntryType"] = "Event"; 407184afc48bSJason M. Bills bmcLogEntry["Severity"] = std::move(severity); 407284afc48bSJason M. Bills bmcLogEntry["Created"] = entryTimeStr; 4073647b3cdcSGeorge Liu if (!std::get<std::vector<uint8_t>>(code.second).empty()) 4074647b3cdcSGeorge Liu { 4075647b3cdcSGeorge Liu bmcLogEntry["AdditionalDataURI"] = 4076647b3cdcSGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" + 4077647b3cdcSGeorge Liu postcodeEntryID + "/attachment"; 4078647b3cdcSGeorge Liu } 40796f284d24SJiaqing Zhao 40806f284d24SJiaqing Zhao // codeIndex is only specified when querying single entry, return only 40816f284d24SJiaqing Zhao // that entry in this case 40826f284d24SJiaqing Zhao if (codeIndex != 0) 40836f284d24SJiaqing Zhao { 4084ac106bf6SEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry); 40856f284d24SJiaqing Zhao return true; 4086a3316fc6SZhikuiRen } 40876f284d24SJiaqing Zhao 4088ac106bf6SEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"]; 4089b2ba3072SPatrick Williams logEntryArray.emplace_back(std::move(bmcLogEntry)); 40906f284d24SJiaqing Zhao } 40916f284d24SJiaqing Zhao 40926f284d24SJiaqing Zhao // Return value is always false when querying multiple entries 40936f284d24SJiaqing Zhao return false; 4094a3316fc6SZhikuiRen } 4095a3316fc6SZhikuiRen 4096ac106bf6SEd Tanous static void 4097ac106bf6SEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40986f284d24SJiaqing Zhao const std::string& entryId) 4099a3316fc6SZhikuiRen { 41006f284d24SJiaqing Zhao uint16_t bootIndex = 0; 41016f284d24SJiaqing Zhao uint64_t codeIndex = 0; 41026f284d24SJiaqing Zhao if (!parsePostCode(entryId, codeIndex, bootIndex)) 41036f284d24SJiaqing Zhao { 41046f284d24SJiaqing Zhao // Requested ID was not found 4105ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41066f284d24SJiaqing Zhao return; 41076f284d24SJiaqing Zhao } 41086f284d24SJiaqing Zhao 41096f284d24SJiaqing Zhao if (bootIndex == 0 || codeIndex == 0) 41106f284d24SJiaqing Zhao { 41116f284d24SJiaqing Zhao // 0 is an invalid index 4112ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41136f284d24SJiaqing Zhao return; 41146f284d24SJiaqing Zhao } 41156f284d24SJiaqing Zhao 4116a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4117ac106bf6SEd Tanous [asyncResp, entryId, bootIndex, 41185e7e2dc5SEd Tanous codeIndex](const boost::system::error_code& ec, 41196c9a279eSManojkiran Eda const boost::container::flat_map< 41206c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41216c9a279eSManojkiran Eda postcode) { 4122a3316fc6SZhikuiRen if (ec) 4123a3316fc6SZhikuiRen { 412462598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4125ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4126a3316fc6SZhikuiRen return; 4127a3316fc6SZhikuiRen } 4128a3316fc6SZhikuiRen 4129a3316fc6SZhikuiRen if (postcode.empty()) 4130a3316fc6SZhikuiRen { 4131ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 4132a3316fc6SZhikuiRen return; 4133a3316fc6SZhikuiRen } 4134a3316fc6SZhikuiRen 4135ac106bf6SEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex)) 41366f284d24SJiaqing Zhao { 4137ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId); 41386f284d24SJiaqing Zhao return; 41396f284d24SJiaqing Zhao } 4140a3316fc6SZhikuiRen }, 414115124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 414215124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4143a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4144a3316fc6SZhikuiRen bootIndex); 4145a3316fc6SZhikuiRen } 4146a3316fc6SZhikuiRen 4147ac106bf6SEd Tanous static void 4148ac106bf6SEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4149ac106bf6SEd Tanous const uint16_t bootIndex, const uint16_t bootCount, 4150ac106bf6SEd Tanous const uint64_t entryCount, size_t skip, size_t top) 4151a3316fc6SZhikuiRen { 4152a3316fc6SZhikuiRen crow::connections::systemBus->async_method_call( 4153ac106bf6SEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip, 41545e7e2dc5SEd Tanous top](const boost::system::error_code& ec, 41556c9a279eSManojkiran Eda const boost::container::flat_map< 41566c9a279eSManojkiran Eda uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& 41576c9a279eSManojkiran Eda postcode) { 4158a3316fc6SZhikuiRen if (ec) 4159a3316fc6SZhikuiRen { 416062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error"); 4161ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4162a3316fc6SZhikuiRen return; 4163a3316fc6SZhikuiRen } 4164a3316fc6SZhikuiRen 4165a3316fc6SZhikuiRen uint64_t endCount = entryCount; 4166a3316fc6SZhikuiRen if (!postcode.empty()) 4167a3316fc6SZhikuiRen { 4168a3316fc6SZhikuiRen endCount = entryCount + postcode.size(); 41693648c8beSEd Tanous if (skip < endCount && (top + skip) > entryCount) 4170a3316fc6SZhikuiRen { 417189492a15SPatrick Williams uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip), 417289492a15SPatrick Williams entryCount) - 41733648c8beSEd Tanous entryCount; 4174a3316fc6SZhikuiRen uint64_t thisBootTop = 41753648c8beSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) - 41763648c8beSEd Tanous entryCount; 4177a3316fc6SZhikuiRen 4178ac106bf6SEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0, 4179ac106bf6SEd Tanous thisBootSkip, thisBootTop); 4180a3316fc6SZhikuiRen } 4181ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount; 4182a3316fc6SZhikuiRen } 4183a3316fc6SZhikuiRen 4184a3316fc6SZhikuiRen // continue to previous bootIndex 4185a3316fc6SZhikuiRen if (bootIndex < bootCount) 4186a3316fc6SZhikuiRen { 4187ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1), 4188a3316fc6SZhikuiRen bootCount, endCount, skip, top); 4189a3316fc6SZhikuiRen } 419081584abeSJiaqing Zhao else if (skip + top < endCount) 4191a3316fc6SZhikuiRen { 4192ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] = 41930fda0f12SGeorge Liu "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" + 4194a3316fc6SZhikuiRen std::to_string(skip + top); 4195a3316fc6SZhikuiRen } 4196a3316fc6SZhikuiRen }, 419715124765SJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 419815124765SJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 4199a3316fc6SZhikuiRen "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp", 4200a3316fc6SZhikuiRen bootIndex); 4201a3316fc6SZhikuiRen } 4202a3316fc6SZhikuiRen 42038d1b46d7Szhanghch05 static void 4204ac106bf6SEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42053648c8beSEd Tanous size_t skip, size_t top) 4206a3316fc6SZhikuiRen { 4207a3316fc6SZhikuiRen uint64_t entryCount = 0; 42081e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint16_t>( 42091e1e598dSJonathan Doman *crow::connections::systemBus, 42101e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode0", 42111e1e598dSJonathan Doman "/xyz/openbmc_project/State/Boot/PostCode0", 42121e1e598dSJonathan Doman "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount", 4213ac106bf6SEd Tanous [asyncResp, entryCount, skip, top](const boost::system::error_code& ec, 42141e1e598dSJonathan Doman const uint16_t bootCount) { 4215a3316fc6SZhikuiRen if (ec) 4216a3316fc6SZhikuiRen { 421762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4218ac106bf6SEd Tanous messages::internalError(asyncResp->res); 4219a3316fc6SZhikuiRen return; 4220a3316fc6SZhikuiRen } 4221ac106bf6SEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top); 42221e1e598dSJonathan Doman }); 4223a3316fc6SZhikuiRen } 4224a3316fc6SZhikuiRen 42257e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app) 4226a3316fc6SZhikuiRen { 42277e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 422822d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/") 4229ed398213SEd Tanous .privileges(redfish::privileges::getLogEntryCollection) 42307e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 423145ca1b86SEd Tanous [&app](const crow::Request& req, 423222d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 423322d268cbSEd Tanous const std::string& systemName) { 4234c937d2bfSEd Tanous query_param::QueryCapabilities capabilities = { 4235c937d2bfSEd Tanous .canDelegateTop = true, 4236c937d2bfSEd Tanous .canDelegateSkip = true, 4237c937d2bfSEd Tanous }; 4238c937d2bfSEd Tanous query_param::Query delegatedQuery; 4239c937d2bfSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation( 42403ba00073SCarson Labrado app, req, asyncResp, delegatedQuery, capabilities)) 424145ca1b86SEd Tanous { 424245ca1b86SEd Tanous return; 424345ca1b86SEd Tanous } 42447f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42457f3e84a1SEd Tanous { 42467f3e84a1SEd Tanous // Option currently returns no systems. TBD 42477f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42487f3e84a1SEd Tanous systemName); 42497f3e84a1SEd Tanous return; 42507f3e84a1SEd Tanous } 425122d268cbSEd Tanous 425222d268cbSEd Tanous if (systemName != "system") 425322d268cbSEd Tanous { 425422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 425522d268cbSEd Tanous systemName); 425622d268cbSEd Tanous return; 425722d268cbSEd Tanous } 4258a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.type"] = 4259a3316fc6SZhikuiRen "#LogEntryCollection.LogEntryCollection"; 4260a3316fc6SZhikuiRen asyncResp->res.jsonValue["@odata.id"] = 4261a3316fc6SZhikuiRen "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"; 4262a3316fc6SZhikuiRen asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries"; 4263a3316fc6SZhikuiRen asyncResp->res.jsonValue["Description"] = 4264a3316fc6SZhikuiRen "Collection of POST Code Log Entries"; 4265a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 4266a3316fc6SZhikuiRen asyncResp->res.jsonValue["Members@odata.count"] = 0; 42673648c8beSEd Tanous size_t skip = delegatedQuery.skip.value_or(0); 42685143f7a5SJiaqing Zhao size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop); 42693648c8beSEd Tanous getCurrentBootNumber(asyncResp, skip, top); 42707e860f15SJohn Edward Broadbent }); 4271a3316fc6SZhikuiRen } 4272a3316fc6SZhikuiRen 4273647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app) 4274647b3cdcSGeorge Liu { 42750fda0f12SGeorge Liu BMCWEB_ROUTE( 42760fda0f12SGeorge Liu app, 427722d268cbSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/") 4278647b3cdcSGeorge Liu .privileges(redfish::privileges::getLogEntry) 4279647b3cdcSGeorge Liu .methods(boost::beast::http::verb::get)( 428045ca1b86SEd Tanous [&app](const crow::Request& req, 4281647b3cdcSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 428222d268cbSEd Tanous const std::string& systemName, 4283647b3cdcSGeorge Liu const std::string& postCodeID) { 42843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 428545ca1b86SEd Tanous { 428645ca1b86SEd Tanous return; 428745ca1b86SEd Tanous } 428872e21377SMatt Spinler if (!http_helpers::isContentTypeAllowed( 428999351cd8SEd Tanous req.getHeaderValue("Accept"), 42904a0e1a0cSEd Tanous http_helpers::ContentType::OctetStream, true)) 4291647b3cdcSGeorge Liu { 4292002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request); 4293647b3cdcSGeorge Liu return; 4294647b3cdcSGeorge Liu } 42957f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 42967f3e84a1SEd Tanous { 42977f3e84a1SEd Tanous // Option currently returns no systems. TBD 42987f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42997f3e84a1SEd Tanous systemName); 43007f3e84a1SEd Tanous return; 43017f3e84a1SEd Tanous } 430222d268cbSEd Tanous if (systemName != "system") 430322d268cbSEd Tanous { 430422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 430522d268cbSEd Tanous systemName); 430622d268cbSEd Tanous return; 430722d268cbSEd Tanous } 4308647b3cdcSGeorge Liu 4309647b3cdcSGeorge Liu uint64_t currentValue = 0; 4310647b3cdcSGeorge Liu uint16_t index = 0; 4311647b3cdcSGeorge Liu if (!parsePostCode(postCodeID, currentValue, index)) 4312647b3cdcSGeorge Liu { 4313002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID); 4314647b3cdcSGeorge Liu return; 4315647b3cdcSGeorge Liu } 4316647b3cdcSGeorge Liu 4317647b3cdcSGeorge Liu crow::connections::systemBus->async_method_call( 4318647b3cdcSGeorge Liu [asyncResp, postCodeID, currentValue]( 43195e7e2dc5SEd Tanous const boost::system::error_code& ec, 4320002d39b4SEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>& 4321002d39b4SEd Tanous postcodes) { 4322647b3cdcSGeorge Liu if (ec.value() == EBADR) 4323647b3cdcSGeorge Liu { 4324002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4325002d39b4SEd Tanous postCodeID); 4326647b3cdcSGeorge Liu return; 4327647b3cdcSGeorge Liu } 4328647b3cdcSGeorge Liu if (ec) 4329647b3cdcSGeorge Liu { 433062598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 4331647b3cdcSGeorge Liu messages::internalError(asyncResp->res); 4332647b3cdcSGeorge Liu return; 4333647b3cdcSGeorge Liu } 4334647b3cdcSGeorge Liu 4335647b3cdcSGeorge Liu size_t value = static_cast<size_t>(currentValue) - 1; 4336002d39b4SEd Tanous if (value == std::string::npos || postcodes.size() < currentValue) 4337647b3cdcSGeorge Liu { 433862598e31SEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value"); 4339002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4340002d39b4SEd Tanous postCodeID); 4341647b3cdcSGeorge Liu return; 4342647b3cdcSGeorge Liu } 4343647b3cdcSGeorge Liu 43449eb808c1SEd Tanous const auto& [tID, c] = postcodes[value]; 434546ff87baSEd Tanous if (c.empty()) 4346647b3cdcSGeorge Liu { 434762598e31SEd Tanous BMCWEB_LOG_WARNING("No found post code data"); 4348002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", 4349002d39b4SEd Tanous postCodeID); 4350647b3cdcSGeorge Liu return; 4351647b3cdcSGeorge Liu } 435246ff87baSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 435346ff87baSEd Tanous const char* d = reinterpret_cast<const char*>(c.data()); 435446ff87baSEd Tanous std::string_view strData(d, c.size()); 4355647b3cdcSGeorge Liu 4356d9f6c621SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 4357647b3cdcSGeorge Liu "application/octet-stream"); 4358d9f6c621SEd Tanous asyncResp->res.addHeader( 4359d9f6c621SEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64"); 436027b0cf90SEd Tanous asyncResp->res.write(crow::utility::base64encode(strData)); 4361647b3cdcSGeorge Liu }, 4362647b3cdcSGeorge Liu "xyz.openbmc_project.State.Boot.PostCode0", 4363647b3cdcSGeorge Liu "/xyz/openbmc_project/State/Boot/PostCode0", 4364002d39b4SEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index); 4365647b3cdcSGeorge Liu }); 4366647b3cdcSGeorge Liu } 4367647b3cdcSGeorge Liu 43687e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app) 4369a3316fc6SZhikuiRen { 43707e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 437122d268cbSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/") 4372ed398213SEd Tanous .privileges(redfish::privileges::getLogEntry) 43737e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 437445ca1b86SEd Tanous [&app](const crow::Request& req, 43757e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 437622d268cbSEd Tanous const std::string& systemName, const std::string& targetID) { 43773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 437845ca1b86SEd Tanous { 437945ca1b86SEd Tanous return; 438045ca1b86SEd Tanous } 43817f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 43827f3e84a1SEd Tanous { 43837f3e84a1SEd Tanous // Option currently returns no systems. TBD 43847f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 43857f3e84a1SEd Tanous systemName); 43867f3e84a1SEd Tanous return; 43877f3e84a1SEd Tanous } 438822d268cbSEd Tanous if (systemName != "system") 438922d268cbSEd Tanous { 439022d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 439122d268cbSEd Tanous systemName); 439222d268cbSEd Tanous return; 439322d268cbSEd Tanous } 439422d268cbSEd Tanous 43956f284d24SJiaqing Zhao getPostCodeForEntry(asyncResp, targetID); 43967e860f15SJohn Edward Broadbent }); 4397a3316fc6SZhikuiRen } 4398a3316fc6SZhikuiRen 43991da66f75SEd Tanous } // namespace redfish 4400