diff options
author | raviteja-b <raviteja28031990@gmail.com> | 2020-02-03 20:53:32 +0300 |
---|---|---|
committer | Ravi Teja <raviteja28031990@gmail.com> | 2020-05-08 11:38:31 +0300 |
commit | c9bb6861cd1bac2e1849b09176564f01c185207c (patch) | |
tree | ce0f1c59130d745294648b1a1c0b49c768d89c9f /redfish-core | |
parent | 8a3bb71ebcdf14dafd5967192f73bf2416e8bb6e (diff) | |
download | bmcweb-c9bb6861cd1bac2e1849b09176564f01c185207c.tar.xz |
Redfish: Log service implementation for system dump
Dump is the debug data collected at any point of time
from the system and is stored in a file
Currently, Redfish doesn't have schema for operations
on debug data(dump).
This commit implements logService for system dump.
we have a DMTF proposal to extend existing LogService schema
for this purpose but its still work in progress,
so moved to oem schema.
below commit has changes to move properties to OEM
https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/30352
Tested By:
GET https://${IP}/redfish/v1/Systems/system/LogServices/SystemDump
DELETE https://${IP}/redfish/v1/Systems/system/LogServices/SystemDump/Entries/<id>
Redfish validator passed.
(above mentioned commit required to pass validator).
Change-Id: I4a4a4083be4556bc46a4335d31ce56f834bd4f5a
Signed-off-by: Ravi Teja <raviteja28031990@gmail.com>
Diffstat (limited to 'redfish-core')
-rw-r--r-- | redfish-core/include/redfish.hpp | 6 | ||||
-rw-r--r-- | redfish-core/lib/log_services.hpp | 331 |
2 files changed, 337 insertions, 0 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index 1f97b18c2b..ce5e5fb649 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -100,6 +100,12 @@ class RedfishService nodes.emplace_back(std::make_unique<PostCodesEntry>(app)); nodes.emplace_back(std::make_unique<PostCodesEntryCollection>(app)); +#ifdef BMCWEB_ENABLE_REDFISH_SYSTEMDUMP_LOG + nodes.emplace_back(std::make_unique<SystemDumpService>(app)); + nodes.emplace_back(std::make_unique<SystemDumpEntryCollection>(app)); + nodes.emplace_back(std::make_unique<SystemDumpEntry>(app)); +#endif + #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES nodes.emplace_back( std::make_unique<JournalEventLogEntryCollection>(app)); diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp index 73a7bb6f4b..767a7fcf14 100644 --- a/redfish-core/lib/log_services.hpp +++ b/redfish-core/lib/log_services.hpp @@ -141,6 +141,30 @@ inline std::string translateSeverityDbusToRedfish(const std::string &s) return ""; } +inline void deleteSystemDumpEntry(crow::Response &res, + const std::string &entryID) +{ + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + auto respHandler = [asyncResp](const boost::system::error_code ec) { + BMCWEB_LOG_DEBUG << "System Dump Entry doDelete callback: Done"; + if (ec) + { + BMCWEB_LOG_ERROR + << "System Dump (DBus) doDelete respHandler got error " << ec; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; + } + + asyncResp->res.result(boost::beast::http::status::ok); + }; + crow::connections::systemBus->async_method_call( + respHandler, "xyz.openbmc_project.Dump.Manager", + "/xyz/openbmc_project/dump/entry/" + entryID, + "xyz.openbmc_project.Object.Delete", "Delete"); +} + static int getJournalMetadata(sd_journal *journal, const std::string_view &field, std::string_view &contents) @@ -503,6 +527,11 @@ class SystemLogServiceCollection : public Node logServiceArray = nlohmann::json::array(); logServiceArray.push_back( {{"@odata.id", "/redfish/v1/Systems/system/LogServices/EventLog"}}); +#ifdef BMCWEB_ENABLE_REDFISH_SYSTEMDUMP_LOG + logServiceArray.push_back( + {{"@odata.id", "/redfish/v1/Systems/system/LogServices/System"}}); +#endif + #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG logServiceArray.push_back( {{"@odata.id", @@ -1523,6 +1552,308 @@ class BMCJournalLogEntry : public Node } }; +class SystemDumpService : public Node +{ + public: + template <typename CrowApp> + SystemDumpService(CrowApp &app) : + Node(app, "/redfish/v1/Systems/system/LogServices/System/") + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, + {boost::beast::http::verb::put, {{"ConfigureManager"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, + {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; + } + + private: + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Systems/system/LogServices/System"; + asyncResp->res.jsonValue["@odata.type"] = + "#LogService.v1_1_0.LogService"; + asyncResp->res.jsonValue["Name"] = "Dump Log Service"; + asyncResp->res.jsonValue["Description"] = "System Dump Log Service"; + asyncResp->res.jsonValue["Id"] = "System"; + asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull"; + asyncResp->res.jsonValue["LogEntryTypes"] = "Dump"; + asyncResp->res.jsonValue["Oem"]["DumpType"] = "System"; + + asyncResp->res.jsonValue["Entries"] = { + {"@odata.id", + "/redfish/v1/Systems/system/LogServices/System/Entries"}}; + asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = { + {"target", "/redfish/v1/Systems/system/LogServices/System/" + "Actions/LogService.ClearLog"}}; + asyncResp->res.jsonValue["Actions"]["#LogService.CreateLog"] = { + {"target", "/redfish/v1/Systems/system/LogServices/System/" + "Actions/LogService.CreateLog"}}; + } +}; + +class SystemDumpEntryCollection : public Node +{ + public: + template <typename CrowApp> + SystemDumpEntryCollection(CrowApp &app) : + Node(app, "/redfish/v1/Systems/system/LogServices/System/Entries/") + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, + {boost::beast::http::verb::put, {{"ConfigureManager"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, + {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; + } + + private: + /** + * Functions triggers appropriate requests on DBus + */ + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + asyncResp->res.jsonValue["@odata.type"] = + "#LogEntryCollection.LogEntryCollection"; + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Systems/system/LogServices/System/Entries"; + asyncResp->res.jsonValue["Name"] = "System Dump Entries"; + asyncResp->res.jsonValue["Description"] = + "Collection of System Dump Entries"; + + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec, + const crow::openbmc_mapper::GetSubTreeType &resp) { + if (ec) + { + BMCWEB_LOG_ERROR << " resp_handler got error " << ec; + messages::internalError(asyncResp->res); + return; + } + + nlohmann::json &logArray = asyncResp->res.jsonValue["Members"]; + logArray = nlohmann::json::array(); + for (auto &object : resp) + { + const std::string &path = + static_cast<const std::string &>(object.first); + std::size_t lastPos = path.rfind("/"); + if (lastPos == std::string::npos) + { + continue; + } + std::string logID = path.substr(lastPos + 1); + logArray.push_back( + {{"@odata.id", "/redfish/v1/Systems/system/LogServices/" + "System/Entries/" + + logID}}); + } + asyncResp->res.jsonValue["Members@odata.count"] = + logArray.size(); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/dump", 0, + std::array<const char *, 1>{ + "xyz.openbmc_project.Dump.Entry.System"}); + } +}; + +class SystemDumpEntry : public Node +{ + public: + SystemDumpEntry(CrowApp &app) : + Node(app, + "/redfish/v1/Systems/system/LogServices/System/Entries/<str>/", + std::string()) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, + {boost::beast::http::verb::put, {{"ConfigureManager"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, + {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; + } + + private: + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + if (params.size() != 1) + { + messages::internalError(asyncResp->res); + return; + } + const std::string &entryID = params[0]; + crow::connections::systemBus->async_method_call( + [asyncResp, entryID](const boost::system::error_code ec, + GetManagedObjectsType &resp) { + if (ec) + { + BMCWEB_LOG_ERROR + << "SystemDumpEntry resp_handler got error " << ec; + messages::internalError(asyncResp->res); + return; + } + + for (auto &objectPath : resp) + { + if (objectPath.first.str.find( + "/xyz/openbmc_project/dump/entry/" + entryID) == + std::string::npos) + { + continue; + } + + bool foundSystemDumpEntry = false; + for (auto &interfaceMap : objectPath.second) + { + if (interfaceMap.first == + "xyz.openbmc_project.Dump.Entry.System") + { + foundSystemDumpEntry = true; + break; + } + } + if (foundSystemDumpEntry == false) + { + BMCWEB_LOG_DEBUG << "Can't find System Dump Entry"; + messages::internalError(asyncResp->res); + return; + } + + std::string timestamp{}; + uint64_t size = 0; + + for (auto &interfaceMap : objectPath.second) + { + if (interfaceMap.first == + "xyz.openbmc_project.Dump.Entry") + { + for (auto &propertyMap : interfaceMap.second) + { + if (propertyMap.first == "Size") + { + auto sizePtr = std::get_if<uint64_t>( + &propertyMap.second); + if (sizePtr == nullptr) + { + messages::propertyMissing( + asyncResp->res, "Size"); + break; + } + size = *sizePtr; + break; + } + } + } + else if (interfaceMap.first == + "xyz.openbmc_project.Time.EpochTime") + { + for (auto &propertyMap : interfaceMap.second) + { + if (propertyMap.first == "Elapsed") + { + const uint64_t *usecsTimeStamp = + std::get_if<uint64_t>( + &propertyMap.second); + if (usecsTimeStamp == nullptr) + { + messages::propertyMissing( + asyncResp->res, "Elapsed"); + break; + } + getTimestampStr(*usecsTimeStamp, timestamp); + break; + } + } + } + } + asyncResp->res.jsonValue = { + {"@odata.type", "#LogEntry.v1_4_0.LogEntry"}, + {"@odata.id", + "/redfish/v1/Systems/system/LogServices/System/" + "Entries/" + + entryID}, + {"Name", "System Dump Entry"}, + {"Id", entryID}, + {"SizeInB", size}, + {"EntryType", "Dump"}, + {"EntryCode", "User generated dump"}, + {"Created", timestamp}}; + + asyncResp->res + .jsonValue["Actions"]["#LogEntry.DownloadLog"] = { + {"target", + "/redfish/v1/Systems/system/LogServices/System/" + "Entries/" + + entryID + "/Actions/LogEntry.DownloadLog"}}; + } + }, + "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump", + "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + } + + void doDelete(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + BMCWEB_LOG_DEBUG << "Do delete single dump entry"; + + auto asyncResp = std::make_shared<AsyncResp>(res); + + if (params.size() != 1) + { + messages::internalError(asyncResp->res); + return; + } + std::string entryID = params[0]; + + crow::connections::systemBus->async_method_call( + [asyncResp, + entryID](const boost::system::error_code ec, + const crow::openbmc_mapper::GetSubTreeType &resp) { + if (ec) + { + BMCWEB_LOG_ERROR << " resp_handler got error " << ec; + messages::internalError(asyncResp->res); + return; + } + + for (auto &object : resp) + { + const std::string &path = + static_cast<const std::string &>(object.first); + + std::size_t pos = path.rfind( + "/xyz/openbmc_project/dump/entry/" + entryID); + if (pos != std::string::npos) + { + deleteSystemDumpEntry(asyncResp->res, entryID); + return; + } + } + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/dump", 0, + std::array<const char *, 1>{ + "xyz.openbmc_project.Dump.Entry.System"}); + } +}; + class CrashdumpService : public Node { public: |