summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorJason M. Bills <jason.m.bills@linux.intel.com>2019-10-08 21:37:48 +0300
committerJason Bills <jason.m.bills@linux.intel.com>2019-10-29 21:42:47 +0300
commite855dd28ff68c13fea57b49f34da9302e6b2f6cd (patch)
tree9887f2fae784e90e1365fe3517e0dbc1540c4da1 /redfish-core
parent3cf8ea3c737098239c9392d991f6ef742ba67061 (diff)
downloadbmcweb-e855dd28ff68c13fea57b49f34da9302e6b2f6cd.tar.xz
Enable autoexpand on the Crashdump LogEntryCollection
The current Crashdump LogEntry contains non-standard properties and could be very large causing problems for autoexpand. This change uses a LogEntry OEM type to specify a URI where the full log can be retrieved and enables autoexpand on the LogEntryCollection. Tested: Passed the Redfish Service Validator. Change-Id: I6a402d216e6d8228ea2825ab4c6d02b9c8023fc5 Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'redfish-core')
-rw-r--r--redfish-core/include/redfish.hpp1
-rw-r--r--redfish-core/lib/log_services.hpp214
2 files changed, 164 insertions, 51 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index b39ea0b126..d537e9a51f 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -105,6 +105,7 @@ class RedfishService
nodes.emplace_back(std::make_unique<CrashdumpService>(app));
nodes.emplace_back(std::make_unique<CrashdumpEntryCollection>(app));
nodes.emplace_back(std::make_unique<CrashdumpEntry>(app));
+ nodes.emplace_back(std::make_unique<CrashdumpFile>(app));
nodes.emplace_back(std::make_unique<OnDemandCrashdump>(app));
#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
nodes.emplace_back(std::make_unique<SendRawPECI>(app));
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index f1bfda6406..5248fb3708 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -1519,6 +1519,104 @@ class CrashdumpService : 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<const std::string *>();
+ 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_<logTime>.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> asyncResp,
+ const std::string &logID,
+ nlohmann::json &logEntryJson)
+{
+ auto getStoredLogCallback = [asyncResp, logID, &logEntryJson](
+ const boost::system::error_code ec,
+ const std::variant<std::string> &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<std::string>(&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.context", "/redfish/v1/$metadata#LogEntry.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)}};
+ };
+ crow::connections::systemBus->async_method_call(
+ std::move(getStoredLogCallback), CrashdumpObject,
+ CrashdumpPath + std::string("/") + logID,
+ "org.freedesktop.DBus.Properties", "Get", CrashdumpInterface, "Log");
+}
+
class CrashdumpEntryCollection : public Node
{
public:
@@ -1564,28 +1662,40 @@ class CrashdumpEntryCollection : public Node
asyncResp->res.jsonValue["@odata.id"] =
"/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
asyncResp->res.jsonValue["@odata.context"] =
- "/redfish/v1/"
- "$metadata#LogEntryCollection.LogEntryCollection";
+ "/redfish/v1/$metadata#LogEntryCollection.LogEntryCollection";
asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
asyncResp->res.jsonValue["Description"] =
"Collection of Crashdump Entries";
nlohmann::json &logEntryArray = asyncResp->res.jsonValue["Members"];
logEntryArray = nlohmann::json::array();
+ std::vector<std::string> logIDs;
+ // Get the list of log entries and build up an empty array big
+ // enough to hold them
for (const std::string &objpath : resp)
{
- // Don't list the on-demand log
+ // Ignore the on-demand log
if (objpath.compare(CrashdumpOnDemandPath) == 0)
{
continue;
}
+
+ // Get the log ID
std::size_t lastPos = objpath.rfind("/");
- if (lastPos != std::string::npos)
+ if (lastPos == std::string::npos)
{
- logEntryArray.push_back(
- {{"@odata.id", "/redfish/v1/Systems/system/LogServices/"
- "Crashdump/Entries/" +
- objpath.substr(lastPos + 1)}});
+ continue;
}
+ logIDs.emplace_back(objpath.substr(lastPos + 1));
+
+ // Add a space for the log entry to the array
+ logEntryArray.push_back({});
+ }
+ // Now go through and set up async calls to fill in the entries
+ size_t index = 0;
+ for (const std::string &logID : logIDs)
+ {
+ // Add the log entry to the array
+ logCrashdumpEntry(asyncResp, logID, logEntryArray[index++]);
}
asyncResp->res.jsonValue["Members@odata.count"] =
logEntryArray.size();
@@ -1599,38 +1709,46 @@ class CrashdumpEntryCollection : public Node
}
};
-std::string getLogCreatedTime(const nlohmann::json &Crashdump)
+class CrashdumpEntry : public Node
{
- nlohmann::json::const_iterator cdIt = Crashdump.find("crashlog_data");
- if (cdIt != Crashdump.end())
+ public:
+ CrashdumpEntry(CrowApp &app) :
+ Node(app,
+ "/redfish/v1/Systems/system/LogServices/Crashdump/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> &params) override
{
- nlohmann::json::const_iterator siIt = cdIt->find("SYSTEM_INFO");
- if (siIt != cdIt->end())
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ if (params.size() != 1)
{
- nlohmann::json::const_iterator tsIt = siIt->find("timestamp");
- if (tsIt != siIt->end())
- {
- const std::string *logTime =
- tsIt->get_ptr<const std::string *>();
- if (logTime != nullptr)
- {
- return *logTime;
- }
- }
+ messages::internalError(asyncResp->res);
+ return;
}
+ const std::string &logID = params[0];
+ logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
}
- BMCWEB_LOG_DEBUG << "failed to find log timestamp";
-
- return std::string();
-}
+};
-class CrashdumpEntry : public Node
+class CrashdumpFile : public Node
{
public:
- CrashdumpEntry(CrowApp &app) :
+ CrashdumpFile(CrowApp &app) :
Node(app,
- "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/",
- std::string())
+ "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/"
+ "<str>/",
+ std::string(), std::string())
{
entityPrivileges = {
{boost::beast::http::verb::get, {{"Login"}}},
@@ -1646,13 +1764,15 @@ class CrashdumpEntry : public Node
const std::vector<std::string> &params) override
{
std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
- if (params.size() != 1)
+ if (params.size() != 2)
{
messages::internalError(asyncResp->res);
return;
}
- const int logId = std::atoi(params[0].c_str());
- auto getStoredLogCallback = [asyncResp, logId](
+ 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<std::string> &resp) {
if (ec)
@@ -1667,29 +1787,21 @@ class CrashdumpEntry : public Node
messages::internalError(asyncResp->res);
return;
}
- nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
- if (j.is_discarded())
+
+ // Verify the file name parameter is correct
+ if (fileName != getLogFileName(getLogCreatedTime(*log)))
{
- messages::internalError(asyncResp->res);
+ messages::resourceMissingAtURI(asyncResp->res, fileName);
return;
}
- std::string t = getLogCreatedTime(j);
- asyncResp->res.jsonValue = {
- {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
- {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
- {"@odata.id",
- "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
- std::to_string(logId)},
- {"Name", "CPU Crashdump"},
- {"Id", logId},
- {"EntryType", "Oem"},
- {"OemRecordFormat", "Intel Crashdump"},
- {"Oem", {{"Intel", std::move(j)}}},
- {"Created", std::move(t)}};
+
+ // Configure this to be a file download when accessed from a browser
+ asyncResp->res.addHeader("Content-Disposition", "attachment");
+ asyncResp->res.body() = *log;
};
crow::connections::systemBus->async_method_call(
std::move(getStoredLogCallback), CrashdumpObject,
- CrashdumpPath + std::string("/") + std::to_string(logId),
+ CrashdumpPath + std::string("/") + logID,
"org.freedesktop.DBus.Properties", "Get", CrashdumpInterface,
"Log");
}