Make bmcweb image upload compatible with upstream.
This change moves the image upload logic out of the intel oem
namespace, and makes it 1:1 compatible with phosphor rest dbus. This
is to allow a seamless transition in the future.
Change-Id: I243237357a672934c05bf072e7ff1a5955af0f5e
diff --git a/include/image_upload.hpp b/include/image_upload.hpp
new file mode 100644
index 0000000..2a95967
--- /dev/null
+++ b/include/image_upload.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <dbus_singleton.hpp>
+#include <cstdio>
+#include <fstream>
+#include <memory>
+#include <crow/app.h>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+
+namespace crow {
+namespace image_upload {
+
+std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
+
+inline void uploadImageHandler(const crow::request& req, crow::response& res,
+ const std::string& filename) {
+ // Only allow one FW update at a time
+ if (fwUpdateMatcher != nullptr) {
+ res.add_header("Retry-After", "30");
+ res.result(boost::beast::http::status::service_unavailable);
+ res.end();
+ return;
+ }
+ // Make this const static so it survives outside this method
+ static boost::asio::deadline_timer timeout(*req.io_service,
+ boost::posix_time::seconds(5));
+
+ timeout.expires_from_now(boost::posix_time::seconds(5));
+
+ timeout.async_wait([&res](const boost::system::error_code& ec) {
+ fwUpdateMatcher = nullptr;
+ if (ec == asio::error::operation_aborted) {
+ // expected, we were canceled before the timer completed.
+ return;
+ }
+ CROW_LOG_ERROR << "Timed out waiting for log event";
+
+ if (ec) {
+ CROW_LOG_ERROR << "Async_wait failed " << ec;
+ return;
+ }
+
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ });
+
+ std::function<void(sdbusplus::message::message&)> callback =
+ [&res](sdbusplus::message::message& m) {
+ CROW_LOG_DEBUG << "Match fired";
+ boost::system::error_code ec;
+ timeout.cancel(ec);
+ if (ec) {
+ CROW_LOG_ERROR << "error canceling timer " << ec;
+ }
+ std::string versionInfo;
+ m.read(versionInfo); // Read in the object path that was just created
+
+ std::size_t index = versionInfo.rfind('/');
+ if (index != std::string::npos) {
+ versionInfo.erase(0, index);
+ }
+ res.json_value = {{"data", std::move(versionInfo)},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+ CROW_LOG_DEBUG << "ending response";
+ res.end();
+ fwUpdateMatcher = nullptr;
+ };
+ fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::system_bus,
+ "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+ "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
+ callback);
+
+ std::string filepath(
+ "/tmp/images/" +
+ boost::uuids::to_string(boost::uuids::random_generator()()));
+ CROW_LOG_DEBUG << "Writing file to " << filepath;
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ out << req.body;
+ out.close();
+}
+
+template <typename... Middlewares>
+void requestRoutes(Crow<Middlewares...>& app) {
+ CROW_ROUTE(app, "/upload/image/<str>")
+ .methods("POST"_method,
+ "PUT"_method)([](const crow::request& req, crow::response& res,
+ const std::string& filename) {
+ uploadImageHandler(req, res, filename);
+ });
+
+ CROW_ROUTE(app, "/upload/image")
+ .methods("POST"_method,
+ "PUT"_method)([](const crow::request& req, crow::response& res) {
+ uploadImageHandler(req, res, "");
+ });
+}
+} // namespace image_upload
+} // namespace crow
diff --git a/include/intel_oem.hpp b/include/intel_oem.hpp
deleted file mode 100644
index f2dc163..0000000
--- a/include/intel_oem.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <dbus_singleton.hpp>
-#include <fstream>
-#include <crow/app.h>
-
-namespace crow {
-namespace intel_oem {
-
-template <typename... Middlewares>
-void request_routes(Crow<Middlewares...>& app) {
- CROW_ROUTE(app, "/intel/firmwareupload")
- .methods(
- "POST"_method)([](const crow::request& req, crow::response& res) {
- std::string filepath("/tmp/fw_update_image");
- std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
- std::ofstream::trunc);
- out << req.body;
- out.close();
- crow::connections::system_bus->async_method_call(
- [&](boost::system::error_code ec) {
- std::cout << "async_method_call callback\n";
- if (ec) {
- std::cerr << "error with async_method_call \n";
- res.json_value["status"] = "Upload failed";
- } else {
- res.json_value["status"] = "Upload Successful";
- }
- res.end();
- },
- "xyz.openbmc_project.fwupdate1.server",
- "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1",
- "start", "file://" + filepath);
-
- });
-}
-} // namespace intel_oem
-} // namespace crow
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index eaaca94..93b3aa6 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -1,7 +1,7 @@
#include <systemd/sd-daemon.h>
#include <dbus_monitor.hpp>
#include <dbus_singleton.hpp>
-#include <intel_oem.hpp>
+#include <image_upload.hpp>
#include <openbmc_dbus_rest.hpp>
#include <persistent_data_middleware.hpp>
#include <redfish_v1.hpp>
@@ -43,7 +43,7 @@
}
int main(int argc, char** argv) {
- crow::logger::setLogLevel(crow::LogLevel::DEBUG);
+ crow::logger::setLogLevel(crow::LogLevel::DEBUG);
auto io = std::make_shared<boost::asio::io_service>();
crow::PersistentData::session_store =
@@ -67,7 +67,7 @@
crow::kvm::request_routes(app);
crow::redfish::request_routes(app);
crow::dbus_monitor::request_routes(app);
- crow::intel_oem::request_routes(app);
+ crow::image_upload::requestRoutes(app);
crow::openbmc_mapper::request_routes(app);
CROW_LOG_INFO << "bmcweb (" << __DATE__ << ": " << __TIME__ << ')';
@@ -80,4 +80,5 @@
app.run();
io->run();
+ crow::connections::system_bus.reset();
}