summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriana Kobylak <anoo@us.ibm.com>2021-01-29 18:01:30 +0300
committerEd Tanous <ed@tanous.net>2021-04-02 21:15:08 +0300
commit400fd1fb4020028ad58b1cfd965f26d21f63b8c8 (patch)
tree5ae7d7ab14cd02d6246bd0c14785a9c1370f1818
parentf86bb901bf02b65ed25bc4545aaebe0f4dc891b3 (diff)
downloadbmcweb-400fd1fb4020028ad58b1cfd965f26d21f63b8c8.tar.xz
log_services: Add download of log entries
Add a GET function for endpoint /redfish/v1/Systems/system/LogServices/EventLog/attachment/<str> which would read the File Path property of the specified entry, encode it as base64, and send it off. This allows the user to offload error logs for analysis and further parsing if needed. An http header of "Accept: application/octet-stream" or the default "*/*" is expected. Tested: - Ran Redfish validator. - Verified the contents of the offloaded file were the same as the file in the BMC, after decoding it with a base64 decoder. curl -k -H "X-Auth-Token: $token" \ https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/attachment/2 - Verified the supported Accept header values, ex: "Accept: application/octet-stream;q=1" "Accept: text/plain;q=0,application/octet-stream;q=1,multipart/form-data;q=2" - Verified an unsupported Accept header returned "Bad Request", ex: curl -k -H "X-Auth-Token: $token" -H "Accept: application/*" curl -k -H "X-Auth-Token: $token" -H "Accept: foo, not/supported" - Verified 404 was returned for a not found endpoint: $ curl -k -H "X-Auth-Token: $token" https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/attachment/foo { "error": { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_1_1.Message", "Message": "The requested resource of type EventLogAttachment named foo was not found.", "MessageArgs": [ "EventLogAttachment", "foo" ], "MessageId": "Base.1.8.1.ResourceNotFound", "MessageSeverity": "Critical", "Resolution": "Provide a valid resource identifier and resubmit the request." } ], "code": "Base.1.8.1.ResourceNotFound", "message": "The requested resource of type EventLogAttachment named foo was not found." } } Change-Id: Id9e2308ebedc70852a2ed62def107648f7e6fb7a Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
-rw-r--r--redfish-core/include/redfish.hpp1
-rw-r--r--redfish-core/lib/log_services.hpp128
2 files changed, 129 insertions, 0 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index a9832f17d5..9c76c5db9b 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -171,6 +171,7 @@ class RedfishService
nodes.emplace_back(std::make_unique<DBusLogServiceActionsClear>(app));
nodes.emplace_back(std::make_unique<DBusEventLogEntryCollection>(app));
nodes.emplace_back(std::make_unique<DBusEventLogEntry>(app));
+ nodes.emplace_back(std::make_unique<DBusEventLogEntryDownload>(app));
#endif
nodes.emplace_back(
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 1d076a3d7b..2a52830097 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -22,9 +22,12 @@
#include "task.hpp"
#include <systemd/sd-journal.h>
+#include <unistd.h>
+#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/beast/core/span.hpp>
+#include <boost/beast/http.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/system/linux_error.hpp>
#include <error_messages.hpp>
@@ -1757,6 +1760,131 @@ class DBusEventLogEntry : public Node
}
};
+class DBusEventLogEntryDownload : public Node
+{
+ public:
+ DBusEventLogEntryDownload(App& app) :
+ Node(
+ app,
+ "/redfish/v1/Systems/system/LogServices/EventLog/attachment/<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)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ std::string_view acceptHeader = req.getHeaderValue("Accept");
+ // The iterators in boost/http/rfc7230.hpp end the string if '/' is
+ // found, so replace it with arbitrary character '|' which is not part
+ // of the Accept header syntax.
+ std::string acceptStr =
+ boost::replace_all_copy(std::string(acceptHeader), "/", "|");
+ boost::beast::http::ext_list acceptTypes{acceptStr};
+ bool supported = false;
+ for (const auto& type : acceptTypes)
+ {
+ if ((type.first == "*|*") ||
+ (type.first == "application|octet-stream"))
+ {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported)
+ {
+ asyncResp->res.result(boost::beast::http::status::bad_request);
+ return;
+ }
+
+ std::string entryID = params[0];
+ dbus::utility::escapePathForDbus(entryID);
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, entryID](const boost::system::error_code ec,
+ const sdbusplus::message::unix_fd& unixfd) {
+ if (ec.value() == EBADR)
+ {
+ messages::resourceNotFound(asyncResp->res,
+ "EventLogAttachment", entryID);
+ return;
+ }
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ int fd = -1;
+ fd = dup(unixfd);
+ if (fd == -1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ long long int size = lseek(fd, 0, SEEK_END);
+ if (size == -1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ // Arbitrary max size of 64kb
+ constexpr int maxFileSize = 65536;
+ if (size > maxFileSize)
+ {
+ BMCWEB_LOG_ERROR
+ << "File size exceeds maximum allowed size of "
+ << maxFileSize;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ std::vector<char> data(static_cast<size_t>(size));
+ long long int rc = lseek(fd, 0, SEEK_SET);
+ if (rc == -1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ rc = read(fd, data.data(), data.size());
+ if ((rc == -1) || (rc != size))
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ close(fd);
+
+ std::string_view strData(data.data(), data.size());
+ std::string output = crow::utility::base64encode(strData);
+
+ asyncResp->res.addHeader("Content-Type",
+ "application/octet-stream");
+ asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
+ asyncResp->res.body() = std::move(output);
+ },
+ "xyz.openbmc_project.Logging",
+ "/xyz/openbmc_project/logging/entry/" + entryID,
+ "xyz.openbmc_project.Logging.Entry", "GetEntry");
+ }
+};
+
class BMCLogServiceCollection : public Node
{
public: