From 7c55dfb33e035f8a31f11fd3e047a4b674f392ac Mon Sep 17 00:00:00 2001 From: Johnathan Mantey Date: Tue, 10 Mar 2020 17:15:28 -0700 Subject: [PATCH] Match BMCWeb crashdump to the D-Bus interface provided by crashdump The crashdump service changed to eliminate hangs, and failures to retrieve the crashdump data. The BMCWeb crashdump handling code has to be aligned with the server. Tested: Confirmed each of the primary functions operates as expected. Getting the collection Getting the entries Forcing an on demand capture Polling for the on demand capture to complete Retrieving the creashdump data Clearing all of the crashdump content Change-Id: Ie8fb48369a782d905b942c1f9bef11f387f6463e Signed-off-by: Johnathan Mantey --- redfish-core/lib/log_services.hpp | 268 +++++++++++++++++------------- 1 file changed, 150 insertions(+), 118 deletions(-) diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp index f864007..4b13897 100644 --- a/redfish-core/lib/log_services.hpp +++ b/redfish-core/lib/log_services.hpp @@ -1575,109 +1575,80 @@ class CrashdumpClear : public Node } }; -std::string getLogCreatedTime(const std::string &crashdump) -{ - nlohmann::json crashdumpJson = - nlohmann::json::parse(crashdump, nullptr, false); - if (crashdumpJson.is_discarded()) - { - return std::string(); - } - - nlohmann::json::const_iterator cdIt = crashdumpJson.find("crash_data"); - if (cdIt == crashdumpJson.end()) - { - return std::string(); - } - - nlohmann::json::const_iterator siIt = cdIt->find("METADATA"); - if (siIt == cdIt->end()) - { - return std::string(); - } - - nlohmann::json::const_iterator tsIt = siIt->find("timestamp"); - if (tsIt == siIt->end()) - { - return std::string(); - } - - const std::string *logTime = tsIt->get_ptr(); - if (logTime == nullptr) - { - return std::string(); - } - - std::string redfishDateTime = *logTime; - if (redfishDateTime.length() > 2) - { - redfishDateTime.insert(redfishDateTime.end() - 2, ':'); - } - - return redfishDateTime; -} - -std::string getLogFileName(const std::string &logTime) -{ - // Set the crashdump file name to "crashdump_.json" using the - // created time without the timezone info - std::string fileTime = logTime; - size_t plusPos = fileTime.rfind('+'); - if (plusPos != std::string::npos) - { - fileTime.erase(plusPos); - } - return "crashdump_" + fileTime + ".json"; -} - static void logCrashdumpEntry(std::shared_ptr asyncResp, const std::string &logID, nlohmann::json &logEntryJson) { - auto getStoredLogCallback = [asyncResp, logID, &logEntryJson]( - const boost::system::error_code ec, - const std::variant &resp) { - if (ec) - { - BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); - if (ec.value() == - boost::system::linux_error::bad_request_descriptor) + auto getStoredLogCallback = + [asyncResp, logID, &logEntryJson]( + const boost::system::error_code ec, + const std::vector> ¶ms) { + if (ec) { - messages::resourceNotFound(asyncResp->res, "LogEntry", logID); + BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); + if (ec.value() == + boost::system::linux_error::bad_request_descriptor) + { + messages::resourceNotFound(asyncResp->res, "LogEntry", + logID); + } + else + { + messages::internalError(asyncResp->res); + } + return; } - else + + std::string timestamp{}; + std::string filename{}; + for (auto property : params) { - messages::internalError(asyncResp->res); + if (property.first == "Timestamp") + { + const std::string *value = + sdbusplus::message::variant_ns::get_if( + &property.second); + if (value != nullptr) + { + timestamp = *value; + } + } + else if (property.first == "Filename") + { + const std::string *value = + sdbusplus::message::variant_ns::get_if( + &property.second); + if (value != nullptr) + { + filename = *value; + } + } } - return; - } - const std::string *log = std::get_if(&resp); - if (log == nullptr) - { - messages::internalError(asyncResp->res); - return; - } - std::string logTime = getLogCreatedTime(*log); - std::string fileName = getLogFileName(logTime); - logEntryJson = { - {"@odata.type", "#LogEntry.v1_4_0.LogEntry"}, - {"@odata.id", - "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + - logID}, - {"Name", "CPU Crashdump"}, - {"Id", logID}, - {"EntryType", "Oem"}, - {"OemRecordFormat", "Crashdump URI"}, - {"Message", - "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + - logID + "/" + fileName}, - {"Created", std::move(logTime)}}; - }; + if (filename.empty() || timestamp.empty()) + { + messages::resourceMissingAtURI(asyncResp->res, logID); + return; + } + + std::string crashdumpURI = + "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + + logID + "/" + filename; + logEntryJson = {{"@odata.type", "#LogEntry.v1_4_0.LogEntry"}, + {"@odata.id", "/redfish/v1/Systems/system/" + "LogServices/Crashdump/Entries/" + + logID}, + {"Name", "CPU Crashdump"}, + {"Id", logID}, + {"EntryType", "Oem"}, + {"OemRecordFormat", "Crashdump URI"}, + {"Message", std::move(crashdumpURI)}, + {"Created", std::move(timestamp)}}; + }; crow::connections::systemBus->async_method_call( std::move(getStoredLogCallback), crashdumpObject, crashdumpPath + std::string("/") + logID, - "org.freedesktop.DBus.Properties", "Get", crashdumpInterface, "Log"); + "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface); } class CrashdumpEntryCollection : public Node @@ -1827,38 +1798,99 @@ class CrashdumpFile : public Node const std::string &logID = params[0]; const std::string &fileName = params[1]; - auto getStoredLogCallback = [asyncResp, logID, fileName]( - const boost::system::error_code ec, - const std::variant &resp) { - if (ec) - { - BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message(); - messages::internalError(asyncResp->res); - return; - } - const std::string *log = std::get_if(&resp); - if (log == nullptr) - { - messages::internalError(asyncResp->res); - return; - } + auto getStoredLogCallback = + [asyncResp, logID, fileName]( + const boost::system::error_code ec, + const std::vector> &resp) { + if (ec) + { + BMCWEB_LOG_DEBUG << "failed to get log ec: " + << ec.message(); + messages::internalError(asyncResp->res); + return; + } - // Verify the file name parameter is correct - if (fileName != getLogFileName(getLogCreatedTime(*log))) - { - messages::resourceMissingAtURI(asyncResp->res, fileName); - return; - } + std::string dbusFilename{}; + std::string dbusTimestamp{}; + std::string dbusFilepath{}; - // Configure this to be a file download when accessed from a browser - asyncResp->res.addHeader("Content-Disposition", "attachment"); - asyncResp->res.body() = *log; - }; + for (auto property : resp) + { + if (property.first == "Timestamp") + { + const std::string *value = + sdbusplus::message::variant_ns::get_if( + &property.second); + if (value != nullptr) + { + dbusTimestamp = *value; + } + } + else if (property.first == "Filename") + { + const std::string *value = + sdbusplus::message::variant_ns::get_if( + &property.second); + if (value != nullptr) + { + dbusFilename = *value; + } + } + else if (property.first == "Log") + { + const std::string *value = + sdbusplus::message::variant_ns::get_if( + &property.second); + if (value != nullptr) + { + dbusFilepath = *value; + } + } + } + + if (dbusFilename.empty() || dbusTimestamp.empty() || + dbusFilepath.empty()) + { + messages::resourceMissingAtURI(asyncResp->res, fileName); + return; + } + + // Verify the file name parameter is correct + if (fileName != dbusFilename) + { + messages::resourceMissingAtURI(asyncResp->res, fileName); + return; + } + + if (!std::filesystem::exists(dbusFilepath)) + { + messages::resourceMissingAtURI(asyncResp->res, fileName); + return; + } + std::ifstream ifs(dbusFilepath, std::ios::in | + std::ios::binary | + std::ios::ate); + std::ifstream::pos_type fileSize = ifs.tellg(); + if (fileSize < 0) + { + messages::generalError(asyncResp->res); + return; + } + ifs.seekg(0, std::ios::beg); + + std::string dumpData; + dumpData.reserve(static_cast(fileSize)); + ifs.read(dumpData.data(), static_cast(fileSize)); + + // Configure this to be a file download when accessed from + // a browser + asyncResp->res.addHeader("Content-Disposition", "attachment"); + asyncResp->res.body() = dumpData.data(); + }; crow::connections::systemBus->async_method_call( std::move(getStoredLogCallback), crashdumpObject, crashdumpPath + std::string("/") + logID, - "org.freedesktop.DBus.Properties", "Get", crashdumpInterface, - "Log"); + "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface); } }; -- 2.25.1