blob: ab2901ee2bd0dfcd4caeb117c6c3983c91990375 [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"
6
Ed Tanousc3ee5222018-05-01 12:58:27 -07007#include <boost/uuid/uuid.hpp>
8#include <boost/uuid/uuid_generators.hpp>
9#include <boost/uuid/uuid_io.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080010#include <sdbusplus/bus/match.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050011
12#include <cstdio>
Ed Tanous1abe55e2018-09-05 08:30:59 -070013#include <fstream>
14#include <memory>
Ed Tanousc3ee5222018-05-01 12:58:27 -070015
Ed Tanous1abe55e2018-09-05 08:30:59 -070016namespace crow
17{
18namespace image_upload
19{
Ed Tanousc3ee5222018-05-01 12:58:27 -070020
Ed Tanouscf9e4172022-12-21 09:30:16 -080021// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050022static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanousc3ee5222018-05-01 12:58:27 -070023
zhanghch058d1b46d2021-04-01 11:18:24 +080024inline void
25 uploadImageHandler(const crow::Request& req,
26 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -070027{
28 // Only allow one FW update at a time
29 if (fwUpdateMatcher != nullptr)
30 {
zhanghch058d1b46d2021-04-01 11:18:24 +080031 asyncResp->res.addHeader("Retry-After", "30");
32 asyncResp->res.result(boost::beast::http::status::service_unavailable);
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 return;
34 }
35 // Make this const static so it survives outside this method
Ed Tanous271584a2019-07-09 16:24:22 -070036 static boost::asio::steady_timer timeout(*req.ioService,
37 std::chrono::seconds(5));
Ed Tanous1abe55e2018-09-05 08:30:59 -070038
Ed Tanous271584a2019-07-09 16:24:22 -070039 timeout.expires_after(std::chrono::seconds(15));
Ed Tanous1abe55e2018-09-05 08:30:59 -070040
zhanghch058d1b46d2021-04-01 11:18:24 +080041 auto timeoutHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanousc3ee5222018-05-01 12:58:27 -070042 fwUpdateMatcher = nullptr;
Ed Tanous23e64202020-09-15 19:21:30 -070043 if (ec == boost::asio::error::operation_aborted)
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 {
45 // expected, we were canceled before the timer completed.
46 return;
47 }
Matt Spinlerc9008502019-01-21 12:21:25 -060048 BMCWEB_LOG_ERROR << "Timed out waiting for Version interface";
Ed Tanousc3ee5222018-05-01 12:58:27 -070049
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 if (ec)
51 {
52 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
53 return;
54 }
55
zhanghch058d1b46d2021-04-01 11:18:24 +080056 asyncResp->res.result(boost::beast::http::status::bad_request);
Ed Tanous14766872022-03-15 10:44:42 -070057 asyncResp->res.jsonValue["data"]["description"] =
58 "Version already exists or failed to be extracted";
59 asyncResp->res.jsonValue["message"] = "400 Bad Request";
60 asyncResp->res.jsonValue["status"] = "error";
Lei YU9f898f82019-03-08 16:52:10 +080061 };
Ed Tanous1abe55e2018-09-05 08:30:59 -070062
Patrick Williams59d494e2022-07-22 19:26:55 -050063 std::function<void(sdbusplus::message_t&)> callback =
64 [asyncResp](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -070065 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanous1abe55e2018-09-05 08:30:59 -070066
Ed Tanous002d39b2022-05-31 08:59:27 -070067 sdbusplus::message::object_path path;
68 dbus::utility::DBusInteracesMap interfaces;
69 m.read(path, interfaces);
Matt Spinlerc9008502019-01-21 12:21:25 -060070
Ed Tanous002d39b2022-05-31 08:59:27 -070071 if (std::find_if(interfaces.begin(), interfaces.end(),
72 [](const auto& i) {
73 return i.first == "xyz.openbmc_project.Software.Version";
74 }) != interfaces.end())
75 {
76 timeout.cancel();
77 std::string leaf = path.filename();
78 if (leaf.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 {
Ed Tanous002d39b2022-05-31 08:59:27 -070080 leaf = path.str;
Ed Tanous1abe55e2018-09-05 08:30:59 -070081 }
Ed Tanous002d39b2022-05-31 08:59:27 -070082
83 asyncResp->res.jsonValue["data"] = leaf;
84 asyncResp->res.jsonValue["message"] = "200 OK";
85 asyncResp->res.jsonValue["status"] = "ok";
86 BMCWEB_LOG_DEBUG << "ending response";
87 fwUpdateMatcher = nullptr;
88 }
89 };
Patrick Williams59d494e2022-07-22 19:26:55 -050090 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Ed Tanous1abe55e2018-09-05 08:30:59 -070091 *crow::connections::systemBus,
92 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
Matt Spinlerc9008502019-01-21 12:21:25 -060093 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 callback);
95
96 std::string filepath(
97 "/tmp/images/" +
98 boost::uuids::to_string(boost::uuids::random_generator()()));
99 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
100 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
101 std::ofstream::trunc);
102 out << req.body;
103 out.close();
Lei YU9f898f82019-03-08 16:52:10 +0800104 timeout.async_wait(timeoutHandler);
Ed Tanousc3ee5222018-05-01 12:58:27 -0700105}
106
Ed Tanous23a21a12020-07-25 04:45:05 +0000107inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108{
109 BMCWEB_ROUTE(app, "/upload/image/<str>")
Ed Tanous432a8902021-06-14 15:28:56 -0700110 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -0700111 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
zhanghch058d1b46d2021-04-01 11:18:24 +0800112 [](const crow::Request& req,
113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
114 const std::string&) { uploadImageHandler(req, asyncResp); });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700115
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116 BMCWEB_ROUTE(app, "/upload/image")
Ed Tanous432a8902021-06-14 15:28:56 -0700117 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -0700118 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
zhanghch058d1b46d2021-04-01 11:18:24 +0800119 [](const crow::Request& req,
120 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700121 uploadImageHandler(req, asyncResp);
122 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700123}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124} // namespace image_upload
125} // namespace crow