blob: c1ec682778f0297b4c7270c77d90e70af0ba53d4 [file] [log] [blame]
Ed Tanousc3ee5222018-05-01 12:58:27 -07001#pragma once
2
Ed Tanousc94ad492019-10-10 15:39:33 -07003#include <app.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -07004
Ed Tanousc3ee5222018-05-01 12:58:27 -07005#include <boost/uuid/uuid.hpp>
6#include <boost/uuid/uuid_generators.hpp>
7#include <boost/uuid/uuid_io.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07008#include <dbus_singleton.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 Tanousc3ee5222018-05-01 12:58:27 -070013
Ed Tanous1abe55e2018-09-05 08:30:59 -070014namespace crow
15{
16namespace image_upload
17{
Ed Tanousc3ee5222018-05-01 12:58:27 -070018
19std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
20
Ed Tanous55c7b7a2018-05-22 15:27:24 -070021inline void uploadImageHandler(const crow::Request& req, crow::Response& res,
Ed Tanous1abe55e2018-09-05 08:30:59 -070022 const std::string& filename)
23{
24 // Only allow one FW update at a time
25 if (fwUpdateMatcher != nullptr)
26 {
27 res.addHeader("Retry-After", "30");
28 res.result(boost::beast::http::status::service_unavailable);
Ed Tanousc3ee5222018-05-01 12:58:27 -070029 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 return;
31 }
32 // Make this const static so it survives outside this method
Ed Tanous271584a2019-07-09 16:24:22 -070033 static boost::asio::steady_timer timeout(*req.ioService,
34 std::chrono::seconds(5));
Ed Tanous1abe55e2018-09-05 08:30:59 -070035
Ed Tanous271584a2019-07-09 16:24:22 -070036 timeout.expires_after(std::chrono::seconds(15));
Ed Tanous1abe55e2018-09-05 08:30:59 -070037
Lei YU9f898f82019-03-08 16:52:10 +080038 auto timeoutHandler = [&res](const boost::system::error_code& ec) {
Ed Tanousc3ee5222018-05-01 12:58:27 -070039 fwUpdateMatcher = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 if (ec == asio::error::operation_aborted)
41 {
42 // expected, we were canceled before the timer completed.
43 return;
44 }
Matt Spinlerc9008502019-01-21 12:21:25 -060045 BMCWEB_LOG_ERROR << "Timed out waiting for Version interface";
Ed Tanousc3ee5222018-05-01 12:58:27 -070046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 if (ec)
48 {
49 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
50 return;
51 }
52
Matt Spinlerc9008502019-01-21 12:21:25 -060053 res.result(boost::beast::http::status::bad_request);
54 res.jsonValue = {
55 {"data",
56 {{"description",
57 "Version already exists or failed to be extracted"}}},
58 {"message", "400 Bad Request"},
59 {"status", "error"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 res.end();
Lei YU9f898f82019-03-08 16:52:10 +080061 };
Ed Tanous1abe55e2018-09-05 08:30:59 -070062
63 std::function<void(sdbusplus::message::message&)> callback =
64 [&res](sdbusplus::message::message& m) {
65 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanous1abe55e2018-09-05 08:30:59 -070066
Matt Spinlerc9008502019-01-21 12:21:25 -060067 sdbusplus::message::object_path path;
68 std::vector<std::pair<
69 std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -080070 std::vector<std::pair<std::string, std::variant<std::string>>>>>
Matt Spinlerc9008502019-01-21 12:21:25 -060071 interfaces;
72 m.read(path, interfaces);
73
74 if (std::find_if(interfaces.begin(), interfaces.end(),
75 [](const auto& i) {
76 return i.first ==
77 "xyz.openbmc_project.Software.Version";
78 }) != interfaces.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 {
Ed Tanous271584a2019-07-09 16:24:22 -070080 timeout.cancel();
Matt Spinlerc9008502019-01-21 12:21:25 -060081
82 std::size_t index = path.str.rfind('/');
83 if (index != std::string::npos)
84 {
85 path.str.erase(0, index + 1);
86 }
87 res.jsonValue = {{"data", std::move(path.str)},
88 {"message", "200 OK"},
89 {"status", "ok"}};
90 BMCWEB_LOG_DEBUG << "ending response";
91 res.end();
92 fwUpdateMatcher = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 };
95 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
96 *crow::connections::systemBus,
97 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
Matt Spinlerc9008502019-01-21 12:21:25 -060098 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
Ed Tanous1abe55e2018-09-05 08:30:59 -070099 callback);
100
101 std::string filepath(
102 "/tmp/images/" +
103 boost::uuids::to_string(boost::uuids::random_generator()()));
104 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
105 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
106 std::ofstream::trunc);
107 out << req.body;
108 out.close();
Lei YU9f898f82019-03-08 16:52:10 +0800109 timeout.async_wait(timeoutHandler);
Ed Tanousc3ee5222018-05-01 12:58:27 -0700110}
111
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500112template <typename... Middlewares>
113void requestRoutes(Crow<Middlewares...>& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114{
115 BMCWEB_ROUTE(app, "/upload/image/<str>")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700116 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -0700117 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
118 [](const crow::Request& req, crow::Response& res,
119 const std::string& filename) {
120 uploadImageHandler(req, res, filename);
121 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700122
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 BMCWEB_ROUTE(app, "/upload/image")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700124 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -0700125 .methods(boost::beast::http::verb::post, boost::beast::http::verb::put)(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 [](const crow::Request& req, crow::Response& res) {
127 uploadImageHandler(req, res, "");
128 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700129}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130} // namespace image_upload
131} // namespace crow