blob: 8b3dc107c9be8d45045a9dca462ee9700ac52a80 [file] [log] [blame]
Ed Tanousc3ee5222018-05-01 12:58:27 -07001#pragma once
2
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "app.hpp"
4#include "dbus_singleton.hpp"
5#include "dbus_utility.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -07006#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08007
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include <sdbusplus/bus/match.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05009
10#include <cstdio>
Ed Tanous1abe55e2018-09-05 08:30:59 -070011#include <fstream>
12#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070013#include <ranges>
Ed Tanousc3ee5222018-05-01 12:58:27 -070014
Ed Tanous1abe55e2018-09-05 08:30:59 -070015namespace crow
16{
17namespace image_upload
18{
Ed Tanousc3ee5222018-05-01 12:58:27 -070019
Ed Tanouscf9e4172022-12-21 09:30:16 -080020// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050021static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanousc3ee5222018-05-01 12:58:27 -070022
zhanghch058d1b46d2021-04-01 11:18:24 +080023inline void
24 uploadImageHandler(const crow::Request& req,
25 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -070026{
27 // Only allow one FW update at a time
28 if (fwUpdateMatcher != nullptr)
29 {
zhanghch058d1b46d2021-04-01 11:18:24 +080030 asyncResp->res.addHeader("Retry-After", "30");
31 asyncResp->res.result(boost::beast::http::status::service_unavailable);
Ed Tanous1abe55e2018-09-05 08:30:59 -070032 return;
33 }
Ed Tanous8e8245d2024-04-11 22:21:38 -070034 if (req.ioService == nullptr)
35 {
36 asyncResp->res.result(
37 boost::beast::http::status::internal_server_error);
38 return;
39 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 // Make this const static so it survives outside this method
Ed Tanous271584a2019-07-09 16:24:22 -070041 static boost::asio::steady_timer timeout(*req.ioService,
42 std::chrono::seconds(5));
Ed Tanous1abe55e2018-09-05 08:30:59 -070043
Ed Tanous271584a2019-07-09 16:24:22 -070044 timeout.expires_after(std::chrono::seconds(15));
Ed Tanous1abe55e2018-09-05 08:30:59 -070045
zhanghch058d1b46d2021-04-01 11:18:24 +080046 auto timeoutHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanousc3ee5222018-05-01 12:58:27 -070047 fwUpdateMatcher = nullptr;
Ed Tanous23e64202020-09-15 19:21:30 -070048 if (ec == boost::asio::error::operation_aborted)
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 {
50 // expected, we were canceled before the timer completed.
51 return;
52 }
Ed Tanous62598e32023-07-17 17:06:25 -070053 BMCWEB_LOG_ERROR("Timed out waiting for Version interface");
Ed Tanousc3ee5222018-05-01 12:58:27 -070054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 if (ec)
56 {
Ed Tanous62598e32023-07-17 17:06:25 -070057 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 return;
59 }
60
zhanghch058d1b46d2021-04-01 11:18:24 +080061 asyncResp->res.result(boost::beast::http::status::bad_request);
Ed Tanous14766872022-03-15 10:44:42 -070062 asyncResp->res.jsonValue["data"]["description"] =
63 "Version already exists or failed to be extracted";
64 asyncResp->res.jsonValue["message"] = "400 Bad Request";
65 asyncResp->res.jsonValue["status"] = "error";
Lei YU9f898f82019-03-08 16:52:10 +080066 };
Ed Tanous1abe55e2018-09-05 08:30:59 -070067
Patrick Williams59d494e2022-07-22 19:26:55 -050068 std::function<void(sdbusplus::message_t&)> callback =
69 [asyncResp](sdbusplus::message_t& m) {
Ed Tanous62598e32023-07-17 17:06:25 -070070 BMCWEB_LOG_DEBUG("Match fired");
Ed Tanous1abe55e2018-09-05 08:30:59 -070071
Ed Tanous002d39b2022-05-31 08:59:27 -070072 sdbusplus::message::object_path path;
Michael Shen80f79a42023-08-24 13:41:53 +000073 dbus::utility::DBusInterfacesMap interfaces;
Ed Tanous002d39b2022-05-31 08:59:27 -070074 m.read(path, interfaces);
Matt Spinlerc9008502019-01-21 12:21:25 -060075
Ed Tanous3544d2a2023-08-06 18:12:20 -070076 if (std::ranges::find_if(interfaces, [](const auto& i) {
Patrick Williams5a39f772023-10-20 11:20:21 -050077 return i.first == "xyz.openbmc_project.Software.Version";
78 }) != interfaces.end())
Ed Tanous002d39b2022-05-31 08:59:27 -070079 {
80 timeout.cancel();
81 std::string leaf = path.filename();
82 if (leaf.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 {
Ed Tanous002d39b2022-05-31 08:59:27 -070084 leaf = path.str;
Ed Tanous1abe55e2018-09-05 08:30:59 -070085 }
Ed Tanous002d39b2022-05-31 08:59:27 -070086
87 asyncResp->res.jsonValue["data"] = leaf;
88 asyncResp->res.jsonValue["message"] = "200 OK";
89 asyncResp->res.jsonValue["status"] = "ok";
Ed Tanous62598e32023-07-17 17:06:25 -070090 BMCWEB_LOG_DEBUG("ending response");
Ed Tanous002d39b2022-05-31 08:59:27 -070091 fwUpdateMatcher = nullptr;
92 }
93 };
Patrick Williams59d494e2022-07-22 19:26:55 -050094 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Ed Tanous1abe55e2018-09-05 08:30:59 -070095 *crow::connections::systemBus,
96 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
Matt Spinlerc9008502019-01-21 12:21:25 -060097 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 callback);
99
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700100 std::string filepath("/tmp/images/" + bmcweb::getRandomUUID());
Ed Tanous62598e32023-07-17 17:06:25 -0700101 BMCWEB_LOG_DEBUG("Writing file to {}", filepath);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
103 std::ofstream::trunc);
Ed Tanous33c6b582023-02-14 15:05:48 -0800104 out << req.body();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 out.close();
Lei YU9f898f82019-03-08 16:52:10 +0800106 timeout.async_wait(timeoutHandler);
Ed Tanousc3ee5222018-05-01 12:58:27 -0700107}
108
Ed Tanous23a21a12020-07-25 04:45:05 +0000109inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110{
111 BMCWEB_ROUTE(app, "/upload/image/<str>")
Ed Tanous432a8902021-06-14 15:28:56 -0700112 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -0700113 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
zhanghch058d1b46d2021-04-01 11:18:24 +0800114 [](const crow::Request& req,
115 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
116 const std::string&) { uploadImageHandler(req, asyncResp); });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700117
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 BMCWEB_ROUTE(app, "/upload/image")
Ed Tanous432a8902021-06-14 15:28:56 -0700119 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -0700120 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
zhanghch058d1b46d2021-04-01 11:18:24 +0800121 [](const crow::Request& req,
122 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 uploadImageHandler(req, asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -0500124 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700125}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126} // namespace image_upload
127} // namespace crow