blob: 677b6d1741d9631a78f0289679240e3709a41bf5 [file] [log] [blame]
Jennifer Lee729dae72018-04-24 15:59:34 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include "node.hpp"
19#include <boost/container/flat_map.hpp>
20
21namespace redfish {
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070022static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
Jennifer Lee729dae72018-04-24 15:59:34 -070023
Jennifer Lee729dae72018-04-24 15:59:34 -070024class UpdateService : public Node {
25 public:
26 UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
27 Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
28 Node::json["@odata.id"] = "/redfish/v1/UpdateService";
29 Node::json["@odata.context"] =
30 "/redfish/v1/$metadata#UpdateService.UpdateService";
31 Node::json["Id"] = "UpdateService";
32 Node::json["Description"] = "Service for Software Update";
33 Node::json["Name"] = "Update Service";
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070034 Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
Ed Tanousc711bf82018-07-30 16:31:33 -070035 // UpdateService cannot be disabled
36 Node::json["ServiceEnabled"] = true;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -070037 Node::json["FirmwareInventory"] = {
38 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Jennifer Lee729dae72018-04-24 15:59:34 -070039
40 entityPrivileges = {
41 {boost::beast::http::verb::get, {{"Login"}}},
42 {boost::beast::http::verb::head, {{"Login"}}},
43 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
44 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
45 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
46 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
47 }
48
49 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -070050 void doGet(crow::Response &res, const crow::Request &req,
Jennifer Lee729dae72018-04-24 15:59:34 -070051 const std::vector<std::string> &params) override {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070052 res.jsonValue = Node::json;
Jennifer Lee729dae72018-04-24 15:59:34 -070053 res.end();
54 }
Ed Tanousc711bf82018-07-30 16:31:33 -070055 static void activateImage(const std::string &objPath) {
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070056 crow::connections::systemBus->async_method_call(
Ed Tanousc711bf82018-07-30 16:31:33 -070057 [objPath](const boost::system::error_code error_code) {
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070058 if (error_code) {
59 BMCWEB_LOG_DEBUG << "error_code = " << error_code;
60 BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
61 }
62 },
Ed Tanousc711bf82018-07-30 16:31:33 -070063 "xyz.openbmc_project.Software.BMC.Updater", objPath,
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070064 "org.freedesktop.DBus.Properties", "Set",
65 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
66 sdbusplus::message::variant<std::string>(
67 "xyz.openbmc_project.Software.Activation.RequestedActivations."
68 "Active"));
69 }
70 void doPost(crow::Response &res, const crow::Request &req,
71 const std::vector<std::string> &params) override {
72 BMCWEB_LOG_DEBUG << "doPost...";
73
74 // Only allow one FW update at a time
75 if (fwUpdateMatcher != nullptr) {
76 res.addHeader("Retry-After", "30");
77 res.result(boost::beast::http::status::service_unavailable);
78 res.jsonValue = messages::serviceTemporarilyUnavailable("3");
79 res.end();
80 return;
81 }
82 // Make this const static so it survives outside this method
83 static boost::asio::deadline_timer timeout(*req.ioService,
84 boost::posix_time::seconds(5));
85
86 timeout.expires_from_now(boost::posix_time::seconds(5));
87
88 timeout.async_wait([&res](const boost::system::error_code &ec) {
89 fwUpdateMatcher = nullptr;
90 if (ec == boost::asio::error::operation_aborted) {
91 // expected, we were canceled before the timer completed.
92 return;
93 }
94 BMCWEB_LOG_ERROR << "Timed out waiting for firmware object being created";
95 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
96 if (ec) {
97 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
98 return;
99 }
100
101 res.result(boost::beast::http::status::internal_server_error);
102 res.jsonValue = redfish::messages::internalError();
103 res.end();
104 });
105
106 auto callback = [&res](sdbusplus::message::message &m) {
107 BMCWEB_LOG_DEBUG << "Match fired";
108 bool flag = false;
109
110 if (m.is_method_error()) {
111 BMCWEB_LOG_DEBUG << "Dbus method error!!!";
112 res.end();
113 return;
114 }
115 std::vector<std::pair<
116 std::string,
117 std::vector<std::pair<std::string,
118 sdbusplus::message::variant<std::string>>>>>
119 interfaces_properties;
120
Ed Tanousc711bf82018-07-30 16:31:33 -0700121 sdbusplus::message::object_path objPath;
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700122
Ed Tanousc711bf82018-07-30 16:31:33 -0700123 m.read(objPath, interfaces_properties); // Read in the object path
124 // that was just created
125 // std::string str_objpath = objPath.str; // keep a copy for
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700126 // constructing response message
Ed Tanousc711bf82018-07-30 16:31:33 -0700127 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; // str_objpath;
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700128 for (auto &interface : interfaces_properties) {
129 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
130
131 if (interface.first == "xyz.openbmc_project.Software.Activation") {
132 // cancel timer only when xyz.openbmc_project.Software.Activation
133 // interface is added
134 boost::system::error_code ec;
135 timeout.cancel(ec);
136 if (ec) {
137 BMCWEB_LOG_ERROR << "error canceling timer " << ec;
138 }
Ed Tanousc711bf82018-07-30 16:31:33 -0700139 UpdateService::activateImage(objPath.str); // str_objpath);
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700140 res.jsonValue = redfish::messages::success();
141 BMCWEB_LOG_DEBUG << "ending response";
142 res.end();
143 fwUpdateMatcher = nullptr;
144 }
145 }
146 };
147
148 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
149 *crow::connections::systemBus,
150 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
151 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
152 callback);
153
154 std::string filepath(
155 "/tmp/images/" +
156 boost::uuids::to_string(boost::uuids::random_generator()()));
157 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
158 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
159 std::ofstream::trunc);
160 out << req.body;
161 out.close();
162 BMCWEB_LOG_DEBUG << "file upload complete!!";
163 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700164};
165
166class SoftwareInventoryCollection : public Node {
167 public:
Jennifer Lee729dae72018-04-24 15:59:34 -0700168 template <typename CrowApp>
169 SoftwareInventoryCollection(CrowApp &app)
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700170 : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") {
Jennifer Lee729dae72018-04-24 15:59:34 -0700171 Node::json["@odata.type"] =
172 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700173 Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
Jennifer Lee729dae72018-04-24 15:59:34 -0700174 Node::json["@odata.context"] =
175 "/redfish/v1/"
176 "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
177 Node::json["Name"] = "Software Inventory Collection";
178
179 entityPrivileges = {
180 {boost::beast::http::verb::get, {{"Login"}}},
181 {boost::beast::http::verb::head, {{"Login"}}},
182 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
183 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
184 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
185 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
186 }
187
188 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700189 void doGet(crow::Response &res, const crow::Request &req,
Jennifer Lee729dae72018-04-24 15:59:34 -0700190 const std::vector<std::string> &params) override {
Ed Tanousc711bf82018-07-30 16:31:33 -0700191 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700192 res.jsonValue = Node::json;
Ed Tanousc711bf82018-07-30 16:31:33 -0700193
194 crow::connections::systemBus->async_method_call(
195 [asyncResp](
196 const boost::system::error_code ec,
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700197 const std::vector<std::pair<
198 std::string,
199 std::vector<std::pair<std::string, std::vector<std::string>>>>>
200 &subtree) {
Ed Tanousc711bf82018-07-30 16:31:33 -0700201 if (ec) {
202 asyncResp->res.result(
203 boost::beast::http::status::internal_server_error);
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700204 return;
Jennifer Lee729dae72018-04-24 15:59:34 -0700205 }
Ed Tanousc711bf82018-07-30 16:31:33 -0700206 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
207 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700208
209 for (auto &obj : subtree) {
210 const std::vector<std::pair<std::string, std::vector<std::string>>>
211 &connections = obj.second;
212
Ed Tanousc711bf82018-07-30 16:31:33 -0700213 for (auto &conn : connections) {
214 const std::string &connectionName = conn.first;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700215 BMCWEB_LOG_DEBUG << "connectionName = " << connectionName;
216 BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700217
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700218 crow::connections::systemBus->async_method_call(
Ed Tanousc711bf82018-07-30 16:31:33 -0700219 [asyncResp](const boost::system::error_code error_code,
220 const VariantType &activation) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700221 BMCWEB_LOG_DEBUG << "safe returned in lambda function";
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700222 if (error_code) {
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700223 asyncResp->res.result(
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700224 boost::beast::http::status::internal_server_error);
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700225 return;
226 }
Ed Tanousc711bf82018-07-30 16:31:33 -0700227
228 const std::string *sw_inv_purpose =
229 mapbox::getPtr<const std::string>(activation);
230 if (sw_inv_purpose == nullptr) {
231 asyncResp->res.result(
232 boost::beast::http::status::internal_server_error);
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700233 return;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700234 }
Ed Tanousc711bf82018-07-30 16:31:33 -0700235 std::size_t last_pos = sw_inv_purpose->rfind(".");
236 if (last_pos == std::string::npos) {
237 asyncResp->res.result(
238 boost::beast::http::status::internal_server_error);
239 return;
240 }
241 nlohmann::json &members =
242 asyncResp->res.jsonValue["Members"];
243 members.push_back(
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700244 {{"@odata.id",
245 "/redfish/v1/UpdateService/FirmwareInventory/" +
Ed Tanousc711bf82018-07-30 16:31:33 -0700246 sw_inv_purpose->substr(last_pos + 1)}});
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700247 asyncResp->res.jsonValue["Members@odata.count"] =
Ed Tanousc711bf82018-07-30 16:31:33 -0700248 members.size();
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700249 },
250 connectionName, obj.first, "org.freedesktop.DBus.Properties",
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700251 "Get", "xyz.openbmc_project.Software.Activation",
252 "Activation");
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700253 }
254 }
Ed Tanousc711bf82018-07-30 16:31:33 -0700255 },
256 "xyz.openbmc_project.ObjectMapper",
257 "/xyz/openbmc_project/object_mapper",
258 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
259 "/xyz/openbmc_project/software", int32_t(1),
260 std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
Jennifer Lee729dae72018-04-24 15:59:34 -0700261 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700262};
Ed Tanousc711bf82018-07-30 16:31:33 -0700263
Jennifer Lee729dae72018-04-24 15:59:34 -0700264class SoftwareInventory : public Node {
265 public:
Jennifer Lee729dae72018-04-24 15:59:34 -0700266 template <typename CrowApp>
267 SoftwareInventory(CrowApp &app)
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700268 : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
Jennifer Lee729dae72018-04-24 15:59:34 -0700269 std::string()) {
270 Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
Jennifer Lee729dae72018-04-24 15:59:34 -0700271 Node::json["@odata.context"] =
272 "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
273 Node::json["Name"] = "Software Inventory";
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700274 Node::json["Updateable"] = false;
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700275 Node::json["Status"]["Health"] = "OK";
276 Node::json["Status"]["HealthRollup"] = "OK";
277 Node::json["Status"]["State"] = "Enabled";
Jennifer Lee729dae72018-04-24 15:59:34 -0700278 entityPrivileges = {
279 {boost::beast::http::verb::get, {{"Login"}}},
280 {boost::beast::http::verb::head, {{"Login"}}},
281 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
282 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
283 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
284 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
285 }
286
287 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700288 void doGet(crow::Response &res, const crow::Request &req,
Jennifer Lee729dae72018-04-24 15:59:34 -0700289 const std::vector<std::string> &params) override {
Ed Tanousc711bf82018-07-30 16:31:33 -0700290 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700291 res.jsonValue = Node::json;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700292
Jennifer Lee729dae72018-04-24 15:59:34 -0700293 if (params.size() != 1) {
294 res.result(boost::beast::http::status::internal_server_error);
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700295 res.jsonValue = messages::internalError();
Jennifer Lee729dae72018-04-24 15:59:34 -0700296 res.end();
297 return;
298 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700299
Ed Tanousc711bf82018-07-30 16:31:33 -0700300 std::shared_ptr<std::string> sw_id =
301 std::make_shared<std::string>(params[0]);
302
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700303 res.jsonValue["@odata.id"] =
Ed Tanousc711bf82018-07-30 16:31:33 -0700304 "/redfish/v1/UpdateService/FirmwareInventory/" + *sw_id;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700305
Ed Tanousc711bf82018-07-30 16:31:33 -0700306 crow::connections::systemBus->async_method_call(
307 [asyncResp, sw_id](
308 const boost::system::error_code ec,
309 const std::vector<std::pair<
310 std::string,
311 std::vector<std::pair<std::string, std::vector<std::string>>>>>
312 &subtree) {
313 BMCWEB_LOG_DEBUG << "doGet callback...";
314 if (ec) {
315 asyncResp->res.result(
316 boost::beast::http::status::internal_server_error);
317 return;
318 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700319
Ed Tanousc711bf82018-07-30 16:31:33 -0700320 for (const std::pair<std::string,
321 std::vector<std::pair<std::string,
322 std::vector<std::string>>>>
323 &obj : subtree) {
324 if (boost::ends_with(obj.first, *sw_id) != true) {
325 continue;
326 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700327
Ed Tanousc711bf82018-07-30 16:31:33 -0700328 if (obj.second.size() <= 1) {
329 continue;
330 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700331
Ed Tanousc711bf82018-07-30 16:31:33 -0700332 crow::connections::systemBus->async_method_call(
333 [asyncResp, sw_id](
334 const boost::system::error_code error_code,
335 const boost::container::flat_map<std::string, VariantType>
336 &propertiesList) {
337 if (error_code) {
338 asyncResp->res.result(
339 boost::beast::http::status::internal_server_error);
340 return;
341 }
342 boost::container::flat_map<std::string,
343 VariantType>::const_iterator it =
344 propertiesList.find("Purpose");
345 if (it == propertiesList.end()) {
346 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
347 asyncResp->res.result(
348 boost::beast::http::status::internal_server_error);
349 return;
350 }
351 const std::string *sw_inv_purpose =
352 mapbox::getPtr<const std::string>(it->second);
353 if (sw_inv_purpose == nullptr) {
354 BMCWEB_LOG_DEBUG << "wrong types for property\"Purpose\"!";
355 asyncResp->res.result(
356 boost::beast::http::status::internal_server_error);
357 return;
358 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700359
Ed Tanousc711bf82018-07-30 16:31:33 -0700360 BMCWEB_LOG_DEBUG << "sw_inv_purpose = " << *sw_inv_purpose;
361 if (boost::ends_with(*sw_inv_purpose, "." + *sw_id)) {
362 it = propertiesList.find("Version");
363 if (it == propertiesList.end()) {
364 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
365 asyncResp->res.result(
366 boost::beast::http::status::internal_server_error);
367 return;
368 }
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700369
Ed Tanousc711bf82018-07-30 16:31:33 -0700370 const std::string *version =
371 mapbox::getPtr<const std::string>(it->second);
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700372
Ed Tanousc711bf82018-07-30 16:31:33 -0700373 if (version != nullptr) {
374 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
375 asyncResp->res.result(
376 boost::beast::http::status::internal_server_error);
377 return;
378 }
379 asyncResp->res.jsonValue["Version"] = *version;
380 asyncResp->res.jsonValue["Id"] = *sw_id;
381 }
382 },
383 obj.second[0].first, obj.first,
384 "org.freedesktop.DBus.Properties", "GetAll",
385 "xyz.openbmc_project.Software.Version");
386 }
387 },
388 "xyz.openbmc_project.ObjectMapper",
389 "/xyz/openbmc_project/object_mapper",
390 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
391 "/xyz/openbmc_project/software", int32_t(1),
392 std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
Jennifer Lee729dae72018-04-24 15:59:34 -0700393 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700394};
395
396} // namespace redfish