blob: 69e5637361fa03af7f12c4b0c5451161b553d45a [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 <cstdio>
9#include <dbus_singleton.hpp>
10#include <fstream>
11#include <memory>
Ed Tanousc3ee5222018-05-01 12:58:27 -070012
Ed Tanous1abe55e2018-09-05 08:30:59 -070013namespace crow
14{
15namespace image_upload
16{
Ed Tanousc3ee5222018-05-01 12:58:27 -070017
18std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
19
Ed Tanous55c7b7a2018-05-22 15:27:24 -070020inline void uploadImageHandler(const crow::Request& req, crow::Response& res,
Ed Tanous1abe55e2018-09-05 08:30:59 -070021 const std::string& filename)
22{
23 // Only allow one FW update at a time
24 if (fwUpdateMatcher != nullptr)
25 {
26 res.addHeader("Retry-After", "30");
27 res.result(boost::beast::http::status::service_unavailable);
Ed Tanousc3ee5222018-05-01 12:58:27 -070028 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -070029 return;
30 }
31 // Make this const static so it survives outside this method
Ed Tanous271584a2019-07-09 16:24:22 -070032 static boost::asio::steady_timer timeout(*req.ioService,
33 std::chrono::seconds(5));
Ed Tanous1abe55e2018-09-05 08:30:59 -070034
Ed Tanous271584a2019-07-09 16:24:22 -070035 timeout.expires_after(std::chrono::seconds(15));
Ed Tanous1abe55e2018-09-05 08:30:59 -070036
Lei YU9f898f82019-03-08 16:52:10 +080037 auto timeoutHandler = [&res](const boost::system::error_code& ec) {
Ed Tanousc3ee5222018-05-01 12:58:27 -070038 fwUpdateMatcher = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070039 if (ec == asio::error::operation_aborted)
40 {
41 // expected, we were canceled before the timer completed.
42 return;
43 }
Matt Spinlerc9008502019-01-21 12:21:25 -060044 BMCWEB_LOG_ERROR << "Timed out waiting for Version interface";
Ed Tanousc3ee5222018-05-01 12:58:27 -070045
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 if (ec)
47 {
48 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
49 return;
50 }
51
Matt Spinlerc9008502019-01-21 12:21:25 -060052 res.result(boost::beast::http::status::bad_request);
53 res.jsonValue = {
54 {"data",
55 {{"description",
56 "Version already exists or failed to be extracted"}}},
57 {"message", "400 Bad Request"},
58 {"status", "error"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 res.end();
Lei YU9f898f82019-03-08 16:52:10 +080060 };
Ed Tanous1abe55e2018-09-05 08:30:59 -070061
62 std::function<void(sdbusplus::message::message&)> callback =
63 [&res](sdbusplus::message::message& m) {
64 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanous1abe55e2018-09-05 08:30:59 -070065
Matt Spinlerc9008502019-01-21 12:21:25 -060066 sdbusplus::message::object_path path;
67 std::vector<std::pair<
68 std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -080069 std::vector<std::pair<std::string, std::variant<std::string>>>>>
Matt Spinlerc9008502019-01-21 12:21:25 -060070 interfaces;
71 m.read(path, interfaces);
72
73 if (std::find_if(interfaces.begin(), interfaces.end(),
74 [](const auto& i) {
75 return i.first ==
76 "xyz.openbmc_project.Software.Version";
77 }) != interfaces.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -070078 {
Ed Tanous271584a2019-07-09 16:24:22 -070079 timeout.cancel();
Matt Spinlerc9008502019-01-21 12:21:25 -060080
81 std::size_t index = path.str.rfind('/');
82 if (index != std::string::npos)
83 {
84 path.str.erase(0, index + 1);
85 }
86 res.jsonValue = {{"data", std::move(path.str)},
87 {"message", "200 OK"},
88 {"status", "ok"}};
89 BMCWEB_LOG_DEBUG << "ending response";
90 res.end();
91 fwUpdateMatcher = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 };
94 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
95 *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
100 std::string filepath(
101 "/tmp/images/" +
102 boost::uuids::to_string(boost::uuids::random_generator()()));
103 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
104 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
105 std::ofstream::trunc);
106 out << req.body;
107 out.close();
Lei YU9f898f82019-03-08 16:52:10 +0800108 timeout.async_wait(timeoutHandler);
Ed Tanousc3ee5222018-05-01 12:58:27 -0700109}
110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
112{
113 BMCWEB_ROUTE(app, "/upload/image/<str>")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700114 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 .methods("POST"_method,
116 "PUT"_method)([](const crow::Request& req, crow::Response& res,
117 const std::string& filename) {
118 uploadImageHandler(req, res, filename);
119 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700120
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 BMCWEB_ROUTE(app, "/upload/image")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700122 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 .methods("POST"_method, "PUT"_method)(
124 [](const crow::Request& req, crow::Response& res) {
125 uploadImageHandler(req, res, "");
126 });
Ed Tanousc3ee5222018-05-01 12:58:27 -0700127}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128} // namespace image_upload
129} // namespace crow