blob: a9174a1e9e8ec65f5e148ca5a1f4d52ebb72e62c [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
Tejas Patild61e5192021-06-04 15:49:35 +053018#include "bmcweb_config.h"
19
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
21#include "dbus_utility.hpp"
22#include "query.hpp"
23#include "registries/privilege_registry.hpp"
24#include "utils/dbus_utils.hpp"
25#include "utils/sw_utils.hpp"
26
Jonathan Doman1e1e5982021-06-11 09:36:17 -070027#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080028#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020029#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace redfish
32{
Ed Tanous27826b52018-10-29 11:40:58 -070033
Andrew Geissler0e7de462019-03-04 19:11:54 -060034// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080035// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050036static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080037// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050038static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060039// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080040// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060041static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050042// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080043// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070044static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050045
John Edward Broadbent7e860f12021-04-08 15:57:16 -070046inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050047{
48 fwUpdateInProgress = false;
49 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070050 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050051}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052inline static void activateImage(const std::string& objPath,
53 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050054{
55 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
56 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000057 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070058 if (errorCode)
59 {
60 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
61 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
62 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050063 },
64 service, objPath, "org.freedesktop.DBus.Properties", "Set",
65 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080066 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080067 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050068}
Andrew Geissler0554c982019-04-23 14:40:12 -050069
70// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
71// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080072static void
73 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050074 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050075{
Ed Tanousb9d36b42022-02-26 21:42:46 -080076 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050077
78 sdbusplus::message::object_path objPath;
79
80 m.read(objPath, interfacesProperties);
81
82 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Ed Tanouse3eb3d62022-12-21 11:56:07 -080083 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050084 {
85 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
86
87 if (interface.first == "xyz.openbmc_project.Software.Activation")
88 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050089 // Retrieve service and activate
90 crow::connections::systemBus->async_method_call(
Ed Tanousa3e65892021-09-16 14:13:20 -070091 [objPath, asyncResp, payload(std::move(payload))](
92 const boost::system::error_code errorCode,
93 const std::vector<
94 std::pair<std::string, std::vector<std::string>>>&
95 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -070096 if (errorCode)
97 {
98 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
99 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -0500100 if (asyncResp)
101 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 messages::internalError(asyncResp->res);
103 }
104 cleanUp();
105 return;
106 }
107 // Ensure we only got one service back
108 if (objInfo.size() != 1)
109 {
110 BMCWEB_LOG_ERROR << "Invalid Object Size "
111 << objInfo.size();
112 if (asyncResp)
113 {
114 messages::internalError(asyncResp->res);
115 }
116 cleanUp();
117 return;
118 }
119 // cancel timer only when
120 // xyz.openbmc_project.Software.Activation interface
121 // is added
122 fwAvailableTimer = nullptr;
123
124 activateImage(objPath.str, objInfo[0].first);
125 if (asyncResp)
126 {
127 std::shared_ptr<task::TaskData> task =
128 task::TaskData::createTask(
129 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500130 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 const std::shared_ptr<task::TaskData>&
132 taskData) {
133 if (ec)
134 {
135 return task::completed;
136 }
137
138 std::string iface;
139 dbus::utility::DBusPropertiesMap values;
140
141 std::string index = std::to_string(taskData->index);
142 msg.read(iface, values);
143
144 if (iface == "xyz.openbmc_project.Software.Activation")
145 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000146 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 for (const auto& property : values)
148 {
149 if (property.first == "Activation")
150 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000151 state = std::get_if<std::string>(
152 &property.second);
153 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700154 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 taskData->messages.emplace_back(
156 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700157 return task::completed;
158 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700159 }
160 }
James Feist32898ce2020-03-10 16:16:52 -0700161
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 if (state == nullptr)
163 {
164 return !task::completed;
165 }
James Feist32898ce2020-03-10 16:16:52 -0700166
Ed Tanous11ba3972022-07-11 09:50:41 -0700167 if (state->ends_with("Invalid") ||
168 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700169 {
170 taskData->state = "Exception";
171 taskData->status = "Warning";
172 taskData->messages.emplace_back(
173 messages::taskAborted(index));
174 return task::completed;
175 }
James Feiste5d50062020-05-11 17:29:00 -0700176
Ed Tanous11ba3972022-07-11 09:50:41 -0700177 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 {
179 taskData->state = "Stopping";
180 taskData->messages.emplace_back(
181 messages::taskPaused(index));
182
183 // its staged, set a long timer to
184 // allow them time to complete the
185 // update (probably cycle the
186 // system) if this expires then
187 // task will be cancelled
188 taskData->extendTimer(std::chrono::hours(5));
189 return !task::completed;
190 }
191
Ed Tanous11ba3972022-07-11 09:50:41 -0700192 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700193 {
194 taskData->messages.emplace_back(
195 messages::taskCompletedOK(index));
196 taskData->state = "Completed";
197 return task::completed;
198 }
199 }
200 else if (
201 iface ==
202 "xyz.openbmc_project.Software.ActivationProgress")
203 {
204
205 const uint8_t* progress = nullptr;
206 for (const auto& property : values)
207 {
208 if (property.first == "Progress")
209 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000210 progress =
211 std::get_if<uint8_t>(&property.second);
212 if (progress == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700213 {
James Feist32898ce2020-03-10 16:16:52 -0700214 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700215 messages::internalError());
216 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700217 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700218 }
219 }
James Feist32898ce2020-03-10 16:16:52 -0700220
Ed Tanous002d39b2022-05-31 08:59:27 -0700221 if (progress == nullptr)
222 {
223 return !task::completed;
224 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000225 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700226 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000227 messages::taskProgressChanged(index,
228 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700229
Ed Tanous002d39b2022-05-31 08:59:27 -0700230 // if we're getting status updates it's
231 // still alive, update timer
232 taskData->extendTimer(std::chrono::minutes(5));
233 }
234
235 // as firmware update often results in a
236 // reboot, the task may never "complete"
237 // unless it is an error
238
239 return !task::completed;
240 },
241 "type='signal',interface='org.freedesktop.DBus.Properties',"
242 "member='PropertiesChanged',path='" +
243 objPath.str + "'");
244 task->startTimer(std::chrono::minutes(5));
245 task->populateResp(asyncResp->res);
246 task->payload.emplace(std::move(payload));
247 }
248 fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500249 },
250 "xyz.openbmc_project.ObjectMapper",
251 "/xyz/openbmc_project/object_mapper",
252 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500253 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500254 "xyz.openbmc_project.Software.Activation"});
Patrick Williams62bafc02022-09-08 17:35:35 -0500255
256 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500257 }
258 }
259}
260
Andrew Geissler0554c982019-04-23 14:40:12 -0500261// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
262// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700263static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800264 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
265 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500266 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500267{
268 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800269 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500270 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500271 if (asyncResp)
272 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500273 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
274 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500275 return;
276 }
277
Andrew Geissler0554c982019-04-23 14:40:12 -0500278 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700279 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500280
Ed Tanous271584a2019-07-09 16:24:22 -0700281 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500282
283 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500284 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700285 cleanUp();
286 if (ec == boost::asio::error::operation_aborted)
287 {
288 // expected, we were canceled before the timer completed.
289 return;
290 }
291 BMCWEB_LOG_ERROR
292 << "Timed out waiting for firmware object being created";
293 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
294 if (ec)
295 {
296 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
297 return;
298 }
299 if (asyncResp)
300 {
301 redfish::messages::internalError(asyncResp->res);
302 }
303 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700304 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500305 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500306 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700307 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500308 };
309
310 fwUpdateInProgress = true;
311
Patrick Williams59d494e2022-07-22 19:26:55 -0500312 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500313 *crow::connections::systemBus,
314 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
315 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
316 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700317
Patrick Williams59d494e2022-07-22 19:26:55 -0500318 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700319 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800320 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
321 "member='InterfacesAdded',"
322 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500323 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
325 interfacesProperties;
326 sdbusplus::message::object_path objPath;
327 m.read(objPath, interfacesProperties);
328 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
329 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
330 interface : interfacesProperties)
331 {
332 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700333 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 for (const std::pair<std::string,
335 dbus::utility::DbusVariantType>& value :
336 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800337 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700338 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800339 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 continue;
341 }
342 const std::string* type =
343 std::get_if<std::string>(&value.second);
344 if (type == nullptr)
345 {
346 // if this was our message, timeout will cover it
347 return;
348 }
349 fwAvailableTimer = nullptr;
350 if (*type ==
351 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
352 {
353 redfish::messages::invalidUpload(asyncResp->res, url,
354 "Invalid archive");
355 }
356 else if (*type ==
357 "xyz.openbmc_project.Software.Image.Error."
358 "ManifestFileFailure")
359 {
360 redfish::messages::invalidUpload(asyncResp->res, url,
361 "Invalid manifest");
362 }
363 else if (
364 *type ==
365 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
366 {
367 redfish::messages::invalidUpload(
368 asyncResp->res, url, "Invalid image format");
369 }
370 else if (
371 *type ==
372 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
373 {
374 redfish::messages::invalidUpload(
375 asyncResp->res, url,
376 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600377
Ed Tanous002d39b2022-05-31 08:59:27 -0700378 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800379 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700380 "uploaded version");
381 }
382 else if (
383 *type ==
384 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
385 {
386 redfish::messages::resourceExhaustion(asyncResp->res,
387 url);
388 }
389 else
390 {
391 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800392 }
393 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600394 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 }
James Feist4cde5d92020-06-11 10:39:55 -0700396 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500397}
Jennifer Lee729dae72018-04-24 15:59:34 -0700398
Andrew Geissler0554c982019-04-23 14:40:12 -0500399/**
400 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
401 * SimpleUpdate action.
402 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700403inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500404{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700405 BMCWEB_ROUTE(
406 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700407 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700408 .methods(boost::beast::http::verb::post)(
409 [&app](const crow::Request& req,
410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000411 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 {
413 return;
414 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700415
Ed Tanous002d39b2022-05-31 08:59:27 -0700416 std::optional<std::string> transferProtocol;
417 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500418
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500420
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 // User can pass in both TransferProtocol and ImageURI parameters or
422 // they can pass in just the ImageURI with the transfer protocol
423 // embedded within it.
424 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
425 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500426
Ed Tanous002d39b2022-05-31 08:59:27 -0700427 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
428 transferProtocol, "ImageURI", imageURI))
429 {
430 BMCWEB_LOG_DEBUG
431 << "Missing TransferProtocol or ImageURI parameter";
432 return;
433 }
434 if (!transferProtocol)
435 {
436 // Must be option 2
437 // Verify ImageURI has transfer protocol in it
438 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500439 if ((separator == std::string::npos) ||
440 ((separator + 1) > imageURI.size()))
441 {
442 messages::actionParameterValueTypeError(
443 asyncResp->res, imageURI, "ImageURI",
444 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700445 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
446 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530447 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530448 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 transferProtocol = imageURI.substr(0, separator);
450 // Ensure protocol is upper case for a common comparison path
451 // below
452 boost::to_upper(*transferProtocol);
453 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
454 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530455
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 // Adjust imageURI to not have the protocol on it for parsing
457 // below
458 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
459 imageURI = imageURI.substr(separator + 3);
460 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
461 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530462
Ed Tanous002d39b2022-05-31 08:59:27 -0700463 // OpenBMC currently only supports TFTP
464 if (*transferProtocol != "TFTP")
465 {
466 messages::actionParameterNotSupported(asyncResp->res,
467 "TransferProtocol",
468 "UpdateService.SimpleUpdate");
469 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
470 << *transferProtocol;
471 return;
472 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700473
Ed Tanous002d39b2022-05-31 08:59:27 -0700474 // Format should be <IP or Hostname>/<file> for imageURI
475 size_t separator = imageURI.find('/');
476 if ((separator == std::string::npos) ||
477 ((separator + 1) > imageURI.size()))
478 {
479 messages::actionParameterValueTypeError(
480 asyncResp->res, imageURI, "ImageURI",
481 "UpdateService.SimpleUpdate");
482 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
483 return;
484 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700485
Ed Tanous002d39b2022-05-31 08:59:27 -0700486 std::string tftpServer = imageURI.substr(0, separator);
487 std::string fwFile = imageURI.substr(separator + 1);
488 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700489
Ed Tanous002d39b2022-05-31 08:59:27 -0700490 // Setup callback for when new software detected
491 // Give TFTP 10 minutes to complete
492 monitorForSoftwareAvailable(
493 asyncResp, req,
494 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
495 600);
496
497 // TFTP can take up to 10 minutes depending on image size and
498 // connection speed. Return to caller as soon as the TFTP operation
499 // has been started. The callback above will ensure the activate
500 // is started once the download has completed
501 redfish::messages::success(asyncResp->res);
502
503 // Call TFTP service
504 crow::connections::systemBus->async_method_call(
505 [](const boost::system::error_code ec) {
506 if (ec)
507 {
508 // messages::internalError(asyncResp->res);
509 cleanUp();
510 BMCWEB_LOG_DEBUG << "error_code = " << ec;
511 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
512 }
513 else
514 {
515 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
516 }
517 },
518 "xyz.openbmc_project.Software.Download",
519 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
520 "DownloadViaTFTP", fwFile, tftpServer);
521
522 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700523 });
524}
525
Ed Tanousc2051d12022-05-11 12:21:55 -0700526inline void
527 handleUpdateServicePost(App& app, const crow::Request& req,
528 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
529{
Carson Labrado3ba00072022-06-06 19:40:56 +0000530 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700531 {
532 return;
533 }
534 BMCWEB_LOG_DEBUG << "doPost...";
535
536 // Setup callback for when new software detected
537 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
538
539 std::string filepath(
540 "/tmp/images/" +
541 boost::uuids::to_string(boost::uuids::random_generator()()));
542 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
543 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
544 std::ofstream::trunc);
545 out << req.body;
546 out.close();
547 BMCWEB_LOG_DEBUG << "file upload complete!!";
548}
549
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700550inline void requestRoutesUpdateService(App& app)
551{
552 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700553 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 .methods(boost::beast::http::verb::get)(
555 [&app](const crow::Request& req,
556 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000557 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700558 {
559 return;
560 }
561 asyncResp->res.jsonValue["@odata.type"] =
562 "#UpdateService.v1_5_0.UpdateService";
563 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
564 asyncResp->res.jsonValue["Id"] = "UpdateService";
565 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
566 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700567
Ed Tanous32ca38a2022-05-11 12:36:59 -0700568#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700569 // See note about later on in this file about why this is neccesary
570 // This is "Wrong" per the standard, but is done temporarily to
571 // avoid noise in failing tests as people transition to having this
572 // option disabled
573 asyncResp->res.addHeader(boost::beast::http::field::allow,
574 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700575#endif
576
Ed Tanous002d39b2022-05-31 08:59:27 -0700577 asyncResp->res.jsonValue["HttpPushUri"] =
578 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700579
Ed Tanous002d39b2022-05-31 08:59:27 -0700580 // UpdateService cannot be disabled
581 asyncResp->res.jsonValue["ServiceEnabled"] = true;
582 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
583 "/redfish/v1/UpdateService/FirmwareInventory";
584 // Get the MaxImageSizeBytes
585 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
586 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530587
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700588#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700589 // Update Actions object.
590 nlohmann::json& updateSvcSimpleUpdate =
591 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
592 updateSvcSimpleUpdate["target"] =
593 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
594 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
595 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700596#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700597 // Get the current ApplyTime value
598 sdbusplus::asio::getProperty<std::string>(
599 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
600 "/xyz/openbmc_project/software/apply_time",
601 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
602 [asyncResp](const boost::system::error_code ec,
603 const std::string& applyTime) {
604 if (ec)
605 {
606 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
607 messages::internalError(asyncResp->res);
608 return;
609 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530610
Ed Tanous002d39b2022-05-31 08:59:27 -0700611 // Store the ApplyTime Value
612 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
613 "RequestedApplyTimes.Immediate")
614 {
615 asyncResp->res.jsonValue["HttpPushUriOptions"]
616 ["HttpPushUriApplyTime"]["ApplyTime"] =
617 "Immediate";
618 }
619 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
620 "RequestedApplyTimes.OnReset")
621 {
622 asyncResp->res.jsonValue["HttpPushUriOptions"]
623 ["HttpPushUriApplyTime"]["ApplyTime"] =
624 "OnReset";
625 }
626 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700627 });
628 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700629 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700630 .methods(boost::beast::http::verb::patch)(
631 [&app](const crow::Request& req,
632 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000633 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700634 {
635 return;
636 }
637 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530638
Ed Tanous002d39b2022-05-31 08:59:27 -0700639 std::optional<nlohmann::json> pushUriOptions;
640 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
641 pushUriOptions))
642 {
643 return;
644 }
645
646 if (pushUriOptions)
647 {
648 std::optional<nlohmann::json> pushUriApplyTime;
649 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
650 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800651 {
652 return;
653 }
654
Ed Tanous002d39b2022-05-31 08:59:27 -0700655 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800656 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 std::optional<std::string> applyTime;
658 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
659 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700661 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700663
Ed Tanous002d39b2022-05-31 08:59:27 -0700664 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700666 std::string applyTimeNewVal;
667 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700668 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700669 applyTimeNewVal =
670 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
671 }
672 else if (applyTime == "OnReset")
673 {
674 applyTimeNewVal =
675 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
676 }
677 else
678 {
679 BMCWEB_LOG_INFO
680 << "ApplyTime value is not in the list of acceptable values";
681 messages::propertyValueNotInList(
682 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700683 return;
684 }
685
Ed Tanous002d39b2022-05-31 08:59:27 -0700686 // Set the requested image apply time value
687 crow::connections::systemBus->async_method_call(
688 [asyncResp](const boost::system::error_code ec) {
689 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700690 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700691 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
692 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700693 return;
694 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700695 messages::success(asyncResp->res);
696 },
697 "xyz.openbmc_project.Settings",
698 "/xyz/openbmc_project/software/apply_time",
699 "org.freedesktop.DBus.Properties", "Set",
700 "xyz.openbmc_project.Software.ApplyTime",
701 "RequestedApplyTime",
702 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700703 }
George Liu0fda0f12021-11-16 10:06:17 +0800704 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 }
George Liu0fda0f12021-11-16 10:06:17 +0800706 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700707
Ed Tanous4dc23f32022-05-11 11:32:19 -0700708// The "old" behavior of the update service URI causes redfish-service validator
709// failures when the Allow header is supported, given that in the spec,
710// UpdateService does not allow POST. in openbmc, we unfortunately reused that
711// resource as our HttpPushUri as well. A number of services, including the
712// openbmc tests, and documentation have hardcoded that erroneous API, instead
713// of relying on HttpPushUri as the spec requires. This option will exist
714// temporarily to allow the old behavior until Q4 2022, at which time it will be
715// removed.
716#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700717 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700718 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700719 .methods(boost::beast::http::verb::post)(
720 [&app](const crow::Request& req,
721 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
722 asyncResp->res.addHeader(
723 boost::beast::http::field::warning,
724 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
725 "the value contained within HttpPushUri.\"");
726 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700727 });
728#endif
729 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
730 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700731 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700732 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700733}
734
735inline void requestRoutesSoftwareInventoryCollection(App& app)
736{
737 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700738 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700739 .methods(boost::beast::http::verb::get)(
740 [&app](const crow::Request& req,
741 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000742 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700743 {
744 return;
745 }
746 asyncResp->res.jsonValue["@odata.type"] =
747 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
748 asyncResp->res.jsonValue["@odata.id"] =
749 "/redfish/v1/UpdateService/FirmwareInventory";
750 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
751
752 crow::connections::systemBus->async_method_call(
753 [asyncResp](
754 const boost::system::error_code ec,
755 const dbus::utility::MapperGetSubTreeResponse& subtree) {
756 if (ec)
757 {
758 messages::internalError(asyncResp->res);
759 return;
760 }
761 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
762 asyncResp->res.jsonValue["Members@odata.count"] = 0;
763
764 for (const auto& obj : subtree)
765 {
766 sdbusplus::message::object_path path(obj.first);
767 std::string swId = path.filename();
768 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700769 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700770 messages::internalError(asyncResp->res);
771 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700772 return;
773 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700774
Ed Tanous002d39b2022-05-31 08:59:27 -0700775 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
776 nlohmann::json::object_t member;
777 member["@odata.id"] =
778 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
779 members.push_back(std::move(member));
780 asyncResp->res.jsonValue["Members@odata.count"] =
781 members.size();
782 }
783 },
784 // Note that only firmware levels associated with a device
785 // are stored under /xyz/openbmc_project/software therefore
786 // to ensure only real FirmwareInventory items are returned,
787 // this full object path must be used here as input to
788 // mapper
789 "xyz.openbmc_project.ObjectMapper",
790 "/xyz/openbmc_project/object_mapper",
791 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
792 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
793 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
794 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700795}
796/* Fill related item links (i.e. bmc, bios) in for inventory */
797inline static void
798 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
799 const std::string& purpose)
800{
Willy Tueee00132022-06-14 14:53:17 -0700801 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700802 {
803 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700804 nlohmann::json::object_t item;
805 item["@odata.id"] = "/redfish/v1/Managers/bmc";
806 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700807 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
808 }
Willy Tueee00132022-06-14 14:53:17 -0700809 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700810 {
811 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700812 nlohmann::json::object_t item;
813 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
814 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800815 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700816 }
817 else
818 {
819 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
820 }
821}
822
Willy Tuaf246602022-06-14 15:51:53 -0700823inline void
824 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
825 const std::string& service, const std::string& path,
826 const std::string& swId)
827{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200828 sdbusplus::asio::getAllProperties(
829 *crow::connections::systemBus, service, path,
830 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700831 [asyncResp,
832 swId](const boost::system::error_code errorCode,
833 const dbus::utility::DBusPropertiesMap& propertiesList) {
834 if (errorCode)
835 {
836 messages::internalError(asyncResp->res);
837 return;
838 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200839
Willy Tuaf246602022-06-14 15:51:53 -0700840 const std::string* swInvPurpose = nullptr;
841 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200842
843 const bool success = sdbusplus::unpackPropertiesNoThrow(
844 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
845 swInvPurpose, "Version", version);
846
847 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700848 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200849 messages::internalError(asyncResp->res);
850 return;
Willy Tuaf246602022-06-14 15:51:53 -0700851 }
852
853 if (swInvPurpose == nullptr)
854 {
855 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
856 messages::internalError(asyncResp->res);
857 return;
858 }
859
860 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
861
862 if (version == nullptr)
863 {
864 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
865
866 messages::internalError(asyncResp->res);
867
868 return;
869 }
870 asyncResp->res.jsonValue["Version"] = *version;
871 asyncResp->res.jsonValue["Id"] = swId;
872
873 // swInvPurpose is of format:
874 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
875 // Translate this to "ABC image"
876 size_t endDesc = swInvPurpose->rfind('.');
877 if (endDesc == std::string::npos)
878 {
879 messages::internalError(asyncResp->res);
880 return;
881 }
882 endDesc++;
883 if (endDesc >= swInvPurpose->size())
884 {
885 messages::internalError(asyncResp->res);
886 return;
887 }
888
889 std::string formatDesc = swInvPurpose->substr(endDesc);
890 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
891 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200892 });
Willy Tuaf246602022-06-14 15:51:53 -0700893}
894
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700895inline void requestRoutesSoftwareInventory(App& app)
896{
897 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700898 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700899 .methods(boost::beast::http::verb::get)(
900 [&app](const crow::Request& req,
901 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
902 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000903 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700904 {
905 return;
906 }
907 std::shared_ptr<std::string> swId =
908 std::make_shared<std::string>(param);
909
910 asyncResp->res.jsonValue["@odata.id"] =
911 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
912
913 crow::connections::systemBus->async_method_call(
914 [asyncResp,
915 swId](const boost::system::error_code ec,
916 const dbus::utility::MapperGetSubTreeResponse& subtree) {
917 BMCWEB_LOG_DEBUG << "doGet callback...";
918 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700919 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700921 return;
922 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700923
Ed Tanous002d39b2022-05-31 08:59:27 -0700924 // Ensure we find our input swId, otherwise return an error
925 bool found = false;
926 for (const std::pair<std::string,
927 std::vector<std::pair<
928 std::string, std::vector<std::string>>>>&
929 obj : subtree)
930 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700931 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700932 {
933 continue;
934 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700935
Ed Tanous002d39b2022-05-31 08:59:27 -0700936 if (obj.second.empty())
937 {
938 continue;
939 }
940
941 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700942 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700943 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
944 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700945 }
946 if (!found)
947 {
948 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
949 messages::resourceMissingAtURI(
950 asyncResp->res, crow::utility::urlFromPieces(
951 "redfish", "v1", "UpdateService",
952 "FirmwareInventory", *swId));
953 return;
954 }
955 asyncResp->res.jsonValue["@odata.type"] =
956 "#SoftwareInventory.v1_1_0.SoftwareInventory";
957 asyncResp->res.jsonValue["Name"] = "Software Inventory";
958 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700959
Ed Tanous002d39b2022-05-31 08:59:27 -0700960 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700961 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700962 },
963 "xyz.openbmc_project.ObjectMapper",
964 "/xyz/openbmc_project/object_mapper",
965 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
966 static_cast<int32_t>(0),
967 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700968 });
969}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700970
971} // namespace redfish