summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redfish-core/include/redfish.hpp13
-rw-r--r--redfish-core/lib/log_services.hpp730
2 files changed, 527 insertions, 216 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 0998634f02..3aef06a126 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -68,14 +68,17 @@ class RedfishService
nodes.emplace_back(
std::make_unique<VlanNetworkInterfaceCollection>(app));
nodes.emplace_back(std::make_unique<LogServiceCollection>(app));
+ nodes.emplace_back(std::make_unique<BMCLogService>(app));
+ nodes.emplace_back(std::make_unique<BMCLogEntryCollection>(app));
+ nodes.emplace_back(std::make_unique<BMCLogEntry>(app));
#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
- nodes.emplace_back(std::make_unique<CpuLogService>(app));
- nodes.emplace_back(std::make_unique<CpuLogEntryCollection>(app));
- nodes.emplace_back(std::make_unique<CpuLogEntry>(app));
- nodes.emplace_back(std::make_unique<ImmediateCpuLog>(app));
+ nodes.emplace_back(std::make_unique<CPULogService>(app));
+ nodes.emplace_back(std::make_unique<CPULogEntryCollection>(app));
+ nodes.emplace_back(std::make_unique<CPULogEntry>(app));
+ nodes.emplace_back(std::make_unique<ImmediateCPULog>(app));
#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
- nodes.emplace_back(std::make_unique<SendRawPeci>(app));
+ nodes.emplace_back(std::make_unique<SendRawPECI>(app));
#endif // BMCWEB_ENABLE_REDFISH_RAW_PECI
#endif // BMCWEB_ENABLE_REDFISH_CPU_LOG
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 37a3a5454f..ee342cfbb9 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -17,7 +17,10 @@
#include "node.hpp"
+#include <systemd/sd-journal.h>
+
#include <boost/container/flat_map.hpp>
+#include <boost/utility/string_view.hpp>
#include <experimental/filesystem>
namespace redfish
@@ -29,7 +32,7 @@ constexpr char const *cpuLogImmediatePath = "/com/intel/CpuDebugLog/Immediate";
constexpr char const *cpuLogInterface = "com.intel.CpuDebugLog";
constexpr char const *cpuLogImmediateInterface =
"com.intel.CpuDebugLog.Immediate";
-constexpr char const *cpuLogRawPeciInterface =
+constexpr char const *cpuLogRawPECIInterface =
"com.intel.CpuDebugLog.SendRawPeci";
namespace fs = std::experimental::filesystem;
@@ -45,12 +48,12 @@ class LogServiceCollection : public Node
// load dynamic data so the duplicate static members don't get displayed
Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
entityPrivileges = {
- {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ {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:
@@ -60,44 +63,346 @@ class LogServiceCollection : public Node
void doGet(crow::Response &res, const crow::Request &req,
const std::vector<std::string> &params) override
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
// Collections don't include the static data added by SubRoute because
// it has a duplicate entry for members
- res.jsonValue["@odata.type"] =
+ asyncResp->res.jsonValue["@odata.type"] =
"#LogServiceCollection.LogServiceCollection";
- res.jsonValue["@odata.context"] =
+ asyncResp->res.jsonValue["@odata.context"] =
"/redfish/v1/"
"$metadata#LogServiceCollection.LogServiceCollection";
- res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
- res.jsonValue["Name"] = "Open BMC Log Services Collection";
- res.jsonValue["Description"] =
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices";
+ asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
+ asyncResp->res.jsonValue["Description"] =
"Collection of LogServices for this Manager";
- nlohmann::json &logserviceArray = res.jsonValue["Members"];
+ nlohmann::json &logserviceArray = asyncResp->res.jsonValue["Members"];
logserviceArray = nlohmann::json::array();
+ logserviceArray.push_back(
+ {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/BmcLog"}});
#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
logserviceArray.push_back(
{{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/CpuLog"}});
#endif
- res.jsonValue["Members@odata.count"] = logserviceArray.size();
- res.end();
+ asyncResp->res.jsonValue["Members@odata.count"] =
+ logserviceArray.size();
}
};
-class CpuLogService : public Node
+class BMCLogService : public Node
{
public:
template <typename CrowApp>
- CpuLogService(CrowApp &app) :
- Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog")
+ BMCLogService(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/bmc/LogServices/BmcLog/")
+ {
+ // Set the id for SubRoute
+ Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/BmcLog";
+ 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
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ // Copy over the static data to include the entries added by SubRoute
+ asyncResp->res.jsonValue = Node::json;
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogService.v1_1_0.LogService";
+ asyncResp->res.jsonValue["@odata.context"] =
+ "/redfish/v1/$metadata#LogService.LogService";
+ asyncResp->res.jsonValue["Name"] = "Open BMC Log Service";
+ asyncResp->res.jsonValue["Description"] = "BMC Log Service";
+ asyncResp->res.jsonValue["Id"] = "BMC Log";
+ asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
+ }
+};
+
+static int fillBMCLogEntryJson(const std::string &bmcLogEntryID,
+ sd_journal *journal,
+ nlohmann::json &bmcLogEntryJson)
+{
+ // Get the Log Entry contents
+ int ret = 0;
+ const char *data = nullptr;
+ size_t length = 0;
+
+ ret =
+ sd_journal_get_data(journal, "MESSAGE", (const void **)&data, &length);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
+ return 1;
+ }
+ boost::string_view msg;
+ msg = boost::string_view(data, length);
+ // Only use the content after the "=" character.
+ msg.remove_prefix(std::min(msg.find("=") + 1, msg.size()));
+
+ // Get the severity from the PRIORITY field
+ boost::string_view priority;
+ int severity = 8; // Default to an invalid priority
+ ret =
+ sd_journal_get_data(journal, "PRIORITY", (const void **)&data, &length);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
+ return 1;
+ }
+ priority = boost::string_view(data, length);
+ // Check length for sanity. Must be a single digit in the form
+ // "PRIORITY=[0-7]"
+ if (priority.size() > sizeof("PRIORITY=0"))
+ {
+ BMCWEB_LOG_ERROR << "Invalid PRIORITY field length";
+ return 1;
+ }
+ // Only use the content after the "=" character.
+ priority.remove_prefix(std::min(priority.find("=") + 1, priority.size()));
+ severity = strtol(priority.data(), nullptr, 10);
+
+ // Get the Created time from the timestamp
+ // Get the entry timestamp
+ uint64_t timestamp = 0;
+ ret = sd_journal_get_realtime_usec(journal, &timestamp);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
+ << strerror(-ret);
+ }
+ time_t t =
+ static_cast<time_t>(timestamp / 1000 / 1000); // Convert from us to s
+ struct tm *loctime = localtime(&t);
+ char entryTime[64] = {};
+ if (NULL != loctime)
+ {
+ strftime(entryTime, sizeof(entryTime), "%FT%T%z", loctime);
+ }
+ // Insert the ':' into the timezone
+ boost::string_view t1(entryTime);
+ boost::string_view t2(entryTime);
+ if (t1.size() > 2 && t2.size() > 2)
+ {
+ t1.remove_suffix(2);
+ t2.remove_prefix(t2.size() - 2);
+ }
+ const std::string entryTimeStr(t1.to_string() + ":" + t2.to_string());
+
+ // Fill in the log entry with the gathered data
+ bmcLogEntryJson = {
+ {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
+ {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries/" +
+ bmcLogEntryID},
+ {"Name", "BMC Journal Entry"},
+ {"Id", bmcLogEntryID},
+ {"Message", msg.to_string()},
+ {"EntryType", "Oem"},
+ {"Severity",
+ severity <= 2 ? "Critical"
+ : severity <= 4 ? "Warning" : severity <= 7 ? "OK" : ""},
+ {"OemRecordFormat", "Intel BMC Journal Entry"},
+ {"Created", std::move(entryTimeStr)}};
+ return 0;
+}
+
+class BMCLogEntryCollection : public Node
+{
+ public:
+ template <typename CrowApp>
+ BMCLogEntryCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries/")
+ {
+ // Collections use static ID for SubRoute to add to its parent, but only
+ // load dynamic data so the duplicate static members don't get displayed
+ Node::json["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices/BmcLog/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:
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ // Collections don't include the static data added by SubRoute because
+ // it has a duplicate entry for members
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogEntryCollection.LogEntryCollection";
+ asyncResp->res.jsonValue["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#LogEntryCollection.LogEntryCollection";
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries";
+ asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
+ asyncResp->res.jsonValue["Description"] =
+ "Collection of BMC Journal Entries";
+ nlohmann::json &logEntryArray = asyncResp->res.jsonValue["Members"];
+ logEntryArray = nlohmann::json::array();
+
+ // Go through the journal and use the timestamp to create a unique ID
+ // for each entry
+ sd_journal *journalTmp = nullptr;
+ int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
+ journalTmp, sd_journal_close);
+ journalTmp = nullptr;
+ uint64_t prevTs = 0;
+ int index = 0;
+ SD_JOURNAL_FOREACH(journal.get())
+ {
+ // Get the entry timestamp
+ uint64_t curTs = 0;
+ ret = sd_journal_get_realtime_usec(journal.get(), &curTs);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
+ << strerror(-ret);
+ continue;
+ }
+ // If the timestamp isn't unique, increment the index
+ if (curTs == prevTs)
+ {
+ index++;
+ }
+ else
+ {
+ // Otherwise, reset it
+ index = 0;
+ }
+ // Save the timestamp
+ prevTs = curTs;
+
+ std::string idStr(std::to_string(curTs));
+ if (index > 0)
+ {
+ idStr += "_" + std::to_string(index);
+ }
+ logEntryArray.push_back({});
+ nlohmann::json &bmcLogEntry = logEntryArray.back();
+ if (fillBMCLogEntryJson(idStr, journal.get(), bmcLogEntry) != 0)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ }
+ asyncResp->res.jsonValue["Members@odata.count"] = logEntryArray.size();
+ }
+};
+
+class BMCLogEntry : public Node
+{
+ public:
+ BMCLogEntry(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/bmc/LogServices/BmcLog/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
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ if (params.size() != 1)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ // Convert the unique ID back to a timestamp to find the entry
+ boost::string_view tsStr(params[0]);
+ boost::string_view indexStr(params[0]);
+ uint64_t ts = 0;
+ uint16_t index = 0;
+ auto underscorePos = tsStr.find("_");
+ if (underscorePos == tsStr.npos)
+ {
+ // Timestamp has no index
+ ts = strtoull(tsStr.data(), nullptr, 10);
+ }
+ else
+ {
+ // Timestamp has an index
+ tsStr.remove_suffix(tsStr.size() - underscorePos + 1);
+ ts = strtoull(tsStr.data(), nullptr, 10);
+ indexStr.remove_prefix(underscorePos + 1);
+ index =
+ static_cast<uint16_t>(strtoul(indexStr.data(), nullptr, 10));
+ }
+
+ sd_journal *journalTmp = nullptr;
+ int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
+ if (ret < 0)
+ {
+ BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
+ journalTmp, sd_journal_close);
+ journalTmp = nullptr;
+ // Go to the timestamp in the log and move to the entry at the index
+ ret = sd_journal_seek_realtime_usec(journal.get(), ts);
+ for (int i = 0; i <= index; i++)
+ {
+ sd_journal_next(journal.get());
+ }
+ if (fillBMCLogEntryJson(params[0], journal.get(),
+ asyncResp->res.jsonValue) != 0)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ }
+};
+
+class CPULogService : public Node
+{
+ public:
+ template <typename CrowApp>
+ CPULogService(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/")
{
// Set the id for SubRoute
Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/CpuLog";
entityPrivileges = {
- {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ {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:
@@ -107,17 +412,20 @@ class CpuLogService : public Node
void doGet(crow::Response &res, const crow::Request &req,
const std::vector<std::string> &params) override
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
// Copy over the static data to include the entries added by SubRoute
- res.jsonValue = Node::json;
- res.jsonValue["@odata.type"] = "#LogService.v1_1_0.LogService";
- res.jsonValue["@odata.context"] = "/redfish/v1/"
- "$metadata#LogService.LogService";
- res.jsonValue["Name"] = "Open BMC CPU Log Service";
- res.jsonValue["Description"] = "CPU Log Service";
- res.jsonValue["Id"] = "CPU Log";
- res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
- res.jsonValue["MaxNumberOfRecords"] = 3;
- res.jsonValue["Actions"] = {
+ asyncResp->res.jsonValue = Node::json;
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogService.v1_1_0.LogService";
+ asyncResp->res.jsonValue["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#LogService.LogService";
+ asyncResp->res.jsonValue["Name"] = "Open BMC CPU Log Service";
+ asyncResp->res.jsonValue["Description"] = "CPU Log Service";
+ asyncResp->res.jsonValue["Id"] = "CPU Log";
+ asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
+ asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
+ asyncResp->res.jsonValue["Actions"] = {
{"Oem",
{{"#CpuLog.Immediate",
{{"target",
@@ -125,34 +433,33 @@ class CpuLogService : public Node
"CpuLog.Immediate"}}}}}};
#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
- res.jsonValue["Actions"]["Oem"].push_back(
+ asyncResp->res.jsonValue["Actions"]["Oem"].push_back(
{"#CpuLog.SendRawPeci",
{{"target",
"/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
"CpuLog.SendRawPeci"}}});
#endif
- res.end();
}
};
-class CpuLogEntryCollection : public Node
+class CPULogEntryCollection : public Node
{
public:
template <typename CrowApp>
- CpuLogEntryCollection(CrowApp &app) :
- Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries")
+ CPULogEntryCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/")
{
// Collections use static ID for SubRoute to add to its parent, but only
// load dynamic data so the duplicate static members don't get displayed
Node::json["@odata.id"] =
"/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
entityPrivileges = {
- {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ {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:
@@ -162,52 +469,55 @@ class CpuLogEntryCollection : public Node
void doGet(crow::Response &res, const crow::Request &req,
const std::vector<std::string> &params) override
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
// Collections don't include the static data added by SubRoute because
// it has a duplicate entry for members
- auto getLogEntriesCallback =
- [&res](const boost::system::error_code ec,
- const std::vector<std::string> &resp) {
- if (ec)
+ auto getLogEntriesCallback = [asyncResp](
+ const boost::system::error_code ec,
+ const std::vector<std::string> &resp) {
+ if (ec)
+ {
+ if (ec.value() !=
+ boost::system::errc::no_such_file_or_directory)
{
- if (ec.value() !=
- boost::system::errc::no_such_file_or_directory)
- {
- BMCWEB_LOG_DEBUG << "failed to get entries ec: "
- << ec.message();
- res.result(
- boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
+ BMCWEB_LOG_DEBUG << "failed to get entries ec: "
+ << ec.message();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
}
- res.jsonValue["@odata.type"] =
- "#LogEntryCollection.LogEntryCollection";
- res.jsonValue["@odata.context"] =
- "/redfish/v1/"
- "$metadata#LogEntryCollection.LogEntryCollection";
- res.jsonValue["Name"] = "Open BMC CPU Log Entries";
- res.jsonValue["Description"] = "Collection of CPU Log Entries";
- nlohmann::json &logentryArray = res.jsonValue["Members"];
- logentryArray = nlohmann::json::array();
- for (const std::string &objpath : resp)
+ }
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#LogEntryCollection.LogEntryCollection";
+ asyncResp->res.jsonValue["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#LogEntryCollection.LogEntryCollection";
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
+ asyncResp->res.jsonValue["Name"] = "Open BMC CPU Log Entries";
+ asyncResp->res.jsonValue["Description"] =
+ "Collection of CPU Log Entries";
+ nlohmann::json &logEntryArray = asyncResp->res.jsonValue["Members"];
+ logEntryArray = nlohmann::json::array();
+ for (const std::string &objpath : resp)
+ {
+ // Don't list the immediate log
+ if (objpath.compare(cpuLogImmediatePath) == 0)
{
- // Don't list the immediate log
- if (objpath.compare(cpuLogImmediatePath) == 0)
- {
- continue;
- }
- std::size_t lastPos = objpath.rfind("/");
- if (lastPos != std::string::npos)
- {
- logentryArray.push_back(
- {{"@odata.id", "/redfish/v1/Managers/bmc/"
- "LogServices/CpuLog/Entries/" +
- objpath.substr(lastPos + 1)}});
- }
+ continue;
}
- res.jsonValue["Members@odata.count"] = logentryArray.size();
- res.end();
- };
+ std::size_t lastPos = objpath.rfind("/");
+ if (lastPos != std::string::npos)
+ {
+ logEntryArray.push_back(
+ {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/"
+ "CpuLog/Entries/" +
+ objpath.substr(lastPos + 1)}});
+ }
+ }
+ asyncResp->res.jsonValue["Members@odata.count"] =
+ logEntryArray.size();
+ };
crow::connections::systemBus->async_method_call(
std::move(getLogEntriesCallback),
"xyz.openbmc_project.ObjectMapper",
@@ -237,73 +547,76 @@ std::string getLogCreatedTime(const nlohmann::json &cpuLog)
return std::string();
}
-class CpuLogEntry : public Node
+class CPULogEntry : public Node
{
public:
- CpuLogEntry(CrowApp &app) :
+ CPULogEntry(CrowApp &app) :
Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/<str>/",
std::string())
{
entityPrivileges = {
- {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ {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
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
if (params.size() != 1)
{
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
return;
}
const uint8_t logId = std::atoi(params[0].c_str());
- auto getStoredLogCallback = [&res,
- logId](const boost::system::error_code ec,
- const sdbusplus::message::variant<
- std::string> &resp) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- const std::string *log = mapbox::getPtr<const std::string>(resp);
- if (log == nullptr)
- {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
- if (j.is_discarded())
- {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- std::string t = getLogCreatedTime(j);
- res.jsonValue = {
- {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
- {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
- {"@odata.id",
- "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/" +
- std::to_string(logId)},
- {"Name", "CPU Debug Log"},
- {"Id", logId},
- {"EntryType", "Oem"},
- {"OemRecordFormat", "Intel CPU Log"},
- {"Oem", {{"Intel", std::move(j)}}},
- {"Created", std::move(t)}};
- res.end();
- };
+ auto getStoredLogCallback =
+ [asyncResp,
+ logId](const boost::system::error_code ec,
+ const sdbusplus::message::variant<std::string> &resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "failed to get log ec: "
+ << ec.message();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ const std::string *log =
+ mapbox::getPtr<const std::string>(resp);
+ if (log == nullptr)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
+ if (j.is_discarded())
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ std::string t = getLogCreatedTime(j);
+ asyncResp->res.jsonValue = {
+ {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.context",
+ "/redfish/v1/$metadata#LogEntry.LogEntry"},
+ {"@odata.id",
+ "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/" +
+ std::to_string(logId)},
+ {"Name", "CPU Debug Log"},
+ {"Id", logId},
+ {"EntryType", "Oem"},
+ {"OemRecordFormat", "Intel CPU Log"},
+ {"Oem", {{"Intel", std::move(j)}}},
+ {"Created", std::move(t)}};
+ };
crow::connections::systemBus->async_method_call(
std::move(getStoredLogCallback), cpuLogObject,
cpuLogPath + std::string("/") + std::to_string(logId),
@@ -311,45 +624,47 @@ class CpuLogEntry : public Node
}
};
-class ImmediateCpuLog : public Node
+class ImmediateCPULog : public Node
{
public:
- ImmediateCpuLog(CrowApp &app) :
+ ImmediateCPULog(CrowApp &app) :
Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
- "CpuLog.Immediate")
+ "CpuLog.Immediate/")
{
entityPrivileges = {
- {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ {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 doPost(crow::Response &res, const crow::Request &req,
const std::vector<std::string> &params) override
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
static std::unique_ptr<sdbusplus::bus::match::match>
immediateLogMatcher;
// Only allow one Immediate Log request at a time
if (immediateLogMatcher != nullptr)
{
- res.addHeader("Retry-After", "30");
- res.result(boost::beast::http::status::service_unavailable);
+ asyncResp->res.addHeader("Retry-After", "30");
+ asyncResp->res.result(
+ boost::beast::http::status::service_unavailable);
messages::addMessageToJson(
- res.jsonValue, messages::serviceTemporarilyUnavailable("30"),
+ asyncResp->res.jsonValue,
+ messages::serviceTemporarilyUnavailable("30"),
"/CpuLog.Immediate");
- res.end();
return;
}
// Make this static so it survives outside this method
static boost::asio::deadline_timer timeout(*req.ioService);
timeout.expires_from_now(boost::posix_time::seconds(30));
- timeout.async_wait([&res](const boost::system::error_code &ec) {
+ timeout.async_wait([asyncResp](const boost::system::error_code &ec) {
immediateLogMatcher = nullptr;
if (ec)
{
@@ -363,11 +678,11 @@ class ImmediateCpuLog : public Node
}
BMCWEB_LOG_ERROR << "Timed out waiting for immediate log";
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
});
- auto immediateLogMatcherCallback = [&res](
+ auto immediateLogMatcherCallback = [asyncResp](
sdbusplus::message::message &m) {
BMCWEB_LOG_DEBUG << "Immediate log available match fired";
boost::system::error_code ec;
@@ -387,8 +702,8 @@ class ImmediateCpuLog : public Node
interfacesAdded[cpuLogInterface]["Log"]);
if (log == nullptr)
{
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
// Careful with immediateLogMatcher. It is a unique_ptr to the
// match object inside which this lambda is executing. Once it
// is set to nullptr, the match object will be destroyed and the
@@ -400,8 +715,8 @@ class ImmediateCpuLog : public Node
nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
if (j.is_discarded())
{
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
// Careful with immediateLogMatcher. It is a unique_ptr to the
// match object inside which this lambda is executing. Once it
// is set to nullptr, the match object will be destroyed and the
@@ -411,7 +726,7 @@ class ImmediateCpuLog : public Node
return;
}
std::string t = getLogCreatedTime(j);
- res.jsonValue = {
+ asyncResp->res.jsonValue = {
{"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
{"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
{"Name", "CPU Debug Log"},
@@ -419,7 +734,6 @@ class ImmediateCpuLog : public Node
{"OemRecordFormat", "Intel CPU Log"},
{"Oem", {{"Intel", std::move(j)}}},
{"Created", std::move(t)}};
- res.end();
// Careful with immediateLogMatcher. It is a unique_ptr to the
// match object inside which this lambda is executing. Once it is
// set to nullptr, the match object will be destroyed and the lambda
@@ -434,25 +748,24 @@ class ImmediateCpuLog : public Node
std::move(immediateLogMatcherCallback));
auto generateImmediateLogCallback =
- [&res](const boost::system::error_code ec,
- const std::string &resp) {
+ [asyncResp](const boost::system::error_code ec,
+ const std::string &resp) {
if (ec)
{
if (ec.value() ==
boost::system::errc::operation_not_supported)
{
messages::addMessageToJson(
- res.jsonValue, messages::resourceInStandby(),
- "/CpuLog.Immediate");
- res.result(
+ asyncResp->res.jsonValue,
+ messages::resourceInStandby(), "/CpuLog.Immediate");
+ asyncResp->res.result(
boost::beast::http::status::service_unavailable);
}
else
{
- res.result(
+ asyncResp->res.result(
boost::beast::http::status::internal_server_error);
}
- res.end();
boost::system::error_code timeoutec;
timeout.cancel(timeoutec);
if (timeoutec)
@@ -470,12 +783,12 @@ class ImmediateCpuLog : public Node
}
};
-class SendRawPeci : public Node
+class SendRawPECI : public Node
{
public:
- SendRawPeci(CrowApp &app) :
+ SendRawPECI(CrowApp &app) :
Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
- "CpuLog.SendRawPeci")
+ "CpuLog.SendRawPeci/")
{
entityPrivileges = {
{boost::beast::http::verb::get, {{"ConfigureComponents"}}},
@@ -490,67 +803,63 @@ class SendRawPeci : public Node
void doPost(crow::Response &res, const crow::Request &req,
const std::vector<std::string> &params) override
{
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
// Get the Raw PECI command from the request
- nlohmann::json rawPeciCmd;
- if (!json_util::processJsonFromRequest(res, req, rawPeciCmd))
+ nlohmann::json rawPECICmd;
+ if (!json_util::processJsonFromRequest(res, req, rawPECICmd))
{
return;
}
// Get the Client Address from the request
- nlohmann::json::const_iterator caIt = rawPeciCmd.find("ClientAddress");
- if (caIt == rawPeciCmd.end())
+ nlohmann::json::const_iterator caIt = rawPECICmd.find("ClientAddress");
+ if (caIt == rawPECICmd.end())
{
messages::addMessageToJson(
- res.jsonValue, messages::propertyMissing("ClientAddress"),
- "/ClientAddress");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.jsonValue,
+ messages::propertyMissing("ClientAddress"), "/ClientAddress");
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
const uint64_t *ca = caIt->get_ptr<const uint64_t *>();
if (ca == nullptr)
{
messages::addMessageToJson(
- res.jsonValue,
+ asyncResp->res.jsonValue,
messages::propertyValueTypeError(caIt->dump(), "ClientAddress"),
"/ClientAddress");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
// Get the Read Length from the request
const uint8_t clientAddress = static_cast<uint8_t>(*ca);
- nlohmann::json::const_iterator rlIt = rawPeciCmd.find("ReadLength");
- if (rlIt == rawPeciCmd.end())
+ nlohmann::json::const_iterator rlIt = rawPECICmd.find("ReadLength");
+ if (rlIt == rawPECICmd.end())
{
- messages::addMessageToJson(res.jsonValue,
+ messages::addMessageToJson(asyncResp->res.jsonValue,
messages::propertyMissing("ReadLength"),
"/ReadLength");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
const uint64_t *rl = rlIt->get_ptr<const uint64_t *>();
if (rl == nullptr)
{
messages::addMessageToJson(
- res.jsonValue,
+ asyncResp->res.jsonValue,
messages::propertyValueTypeError(rlIt->dump(), "ReadLength"),
"/ReadLength");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
// Get the PECI Command from the request
const uint32_t readLength = static_cast<uint32_t>(*rl);
- nlohmann::json::const_iterator pcIt = rawPeciCmd.find("PECICommand");
- if (pcIt == rawPeciCmd.end())
+ nlohmann::json::const_iterator pcIt = rawPECICmd.find("PECICommand");
+ if (pcIt == rawPECICmd.end())
{
- messages::addMessageToJson(res.jsonValue,
+ messages::addMessageToJson(asyncResp->res.jsonValue,
messages::propertyMissing("PECICommand"),
"/PECICommand");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
std::vector<uint8_t> peciCommand;
@@ -560,36 +869,35 @@ class SendRawPeci : public Node
if (val == nullptr)
{
messages::addMessageToJson(
- res.jsonValue,
+ asyncResp->res.jsonValue,
messages::propertyValueTypeError(
pc.dump(),
"PECICommand/" + std::to_string(peciCommand.size())),
"/PECICommand");
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::bad_request);
return;
}
peciCommand.push_back(static_cast<uint8_t>(*val));
}
// Callback to return the Raw PECI response
- auto sendRawPeciCallback = [&res](const boost::system::error_code ec,
- const std::vector<uint8_t> &resp) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG << "failed to send PECI command ec: "
- << ec.message();
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- res.jsonValue = {{"Name", "PECI Command Response"},
- {"PECIResponse", resp}};
- res.end();
- };
+ auto sendRawPECICallback =
+ [asyncResp](const boost::system::error_code ec,
+ const std::vector<uint8_t> &resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "failed to send PECI command ec: "
+ << ec.message();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ asyncResp->res.jsonValue = {{"Name", "PECI Command Response"},
+ {"PECIResponse", resp}};
+ };
// Call the SendRawPECI command with the provided data
crow::connections::systemBus->async_method_call(
- std::move(sendRawPeciCallback), cpuLogObject, cpuLogPath,
- cpuLogRawPeciInterface, "SendRawPeci", clientAddress, readLength,
+ std::move(sendRawPECICallback), cpuLogObject, cpuLogPath,
+ cpuLogRawPECIInterface, "SendRawPeci", clientAddress, readLength,
peciCommand);
}
};