blob: a8f0a6caa492c7f2bb70b5e6279e5f39e06f1237 [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
George Liu2b731192023-01-11 16:27:13 +080031#include <array>
32#include <string_view>
33
Ed Tanous1abe55e2018-09-05 08:30:59 -070034namespace redfish
35{
Ed Tanous27826b52018-10-29 11:40:58 -070036
Andrew Geissler0e7de462019-03-04 19:11:54 -060037// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080038// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050039static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080040// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050041static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060042// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080043// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060044static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050045// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080046// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070047static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050048
John Edward Broadbent7e860f12021-04-08 15:57:16 -070049inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050050{
51 fwUpdateInProgress = false;
52 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070053 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050054}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070055inline static void activateImage(const std::string& objPath,
56 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050057{
58 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
59 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000060 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070061 if (errorCode)
62 {
63 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
64 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
65 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050066 },
67 service, objPath, "org.freedesktop.DBus.Properties", "Set",
68 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080069 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080070 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050071}
Andrew Geissler0554c982019-04-23 14:40:12 -050072
73// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
74// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080075static void
76 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050077 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050078{
Ed Tanousb9d36b42022-02-26 21:42:46 -080079 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050080
81 sdbusplus::message::object_path objPath;
82
83 m.read(objPath, interfacesProperties);
84
85 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Ed Tanouse3eb3d62022-12-21 11:56:07 -080086 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050087 {
88 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
89
90 if (interface.first == "xyz.openbmc_project.Software.Activation")
91 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050092 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +080093 constexpr std::array<std::string_view, 1> interfaces = {
94 "xyz.openbmc_project.Software.Activation"};
95 dbus::utility::getDbusObject(
96 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -070097 [objPath, asyncResp, payload(std::move(payload))](
George Liu2b731192023-01-11 16:27:13 +080098 const boost::system::error_code& errorCode,
Ed Tanousa3e65892021-09-16 14:13:20 -070099 const std::vector<
100 std::pair<std::string, std::vector<std::string>>>&
101 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 if (errorCode)
103 {
104 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
105 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -0500106 if (asyncResp)
107 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700108 messages::internalError(asyncResp->res);
109 }
110 cleanUp();
111 return;
112 }
113 // Ensure we only got one service back
114 if (objInfo.size() != 1)
115 {
116 BMCWEB_LOG_ERROR << "Invalid Object Size "
117 << objInfo.size();
118 if (asyncResp)
119 {
120 messages::internalError(asyncResp->res);
121 }
122 cleanUp();
123 return;
124 }
125 // cancel timer only when
126 // xyz.openbmc_project.Software.Activation interface
127 // is added
128 fwAvailableTimer = nullptr;
129
130 activateImage(objPath.str, objInfo[0].first);
131 if (asyncResp)
132 {
133 std::shared_ptr<task::TaskData> task =
134 task::TaskData::createTask(
135 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500136 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700137 const std::shared_ptr<task::TaskData>&
138 taskData) {
139 if (ec)
140 {
141 return task::completed;
142 }
143
144 std::string iface;
145 dbus::utility::DBusPropertiesMap values;
146
147 std::string index = std::to_string(taskData->index);
148 msg.read(iface, values);
149
150 if (iface == "xyz.openbmc_project.Software.Activation")
151 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000152 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700153 for (const auto& property : values)
154 {
155 if (property.first == "Activation")
156 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000157 state = std::get_if<std::string>(
158 &property.second);
159 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700160 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 taskData->messages.emplace_back(
162 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700163 return task::completed;
164 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700165 }
166 }
James Feist32898ce2020-03-10 16:16:52 -0700167
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 if (state == nullptr)
169 {
170 return !task::completed;
171 }
James Feist32898ce2020-03-10 16:16:52 -0700172
Ed Tanous11ba3972022-07-11 09:50:41 -0700173 if (state->ends_with("Invalid") ||
174 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 {
176 taskData->state = "Exception";
177 taskData->status = "Warning";
178 taskData->messages.emplace_back(
179 messages::taskAborted(index));
180 return task::completed;
181 }
James Feiste5d50062020-05-11 17:29:00 -0700182
Ed Tanous11ba3972022-07-11 09:50:41 -0700183 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700184 {
185 taskData->state = "Stopping";
186 taskData->messages.emplace_back(
187 messages::taskPaused(index));
188
189 // its staged, set a long timer to
190 // allow them time to complete the
191 // update (probably cycle the
192 // system) if this expires then
193 // task will be cancelled
194 taskData->extendTimer(std::chrono::hours(5));
195 return !task::completed;
196 }
197
Ed Tanous11ba3972022-07-11 09:50:41 -0700198 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700199 {
200 taskData->messages.emplace_back(
201 messages::taskCompletedOK(index));
202 taskData->state = "Completed";
203 return task::completed;
204 }
205 }
206 else if (
207 iface ==
208 "xyz.openbmc_project.Software.ActivationProgress")
209 {
210
211 const uint8_t* progress = nullptr;
212 for (const auto& property : values)
213 {
214 if (property.first == "Progress")
215 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000216 progress =
217 std::get_if<uint8_t>(&property.second);
218 if (progress == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700219 {
James Feist32898ce2020-03-10 16:16:52 -0700220 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700221 messages::internalError());
222 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700223 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700224 }
225 }
James Feist32898ce2020-03-10 16:16:52 -0700226
Ed Tanous002d39b2022-05-31 08:59:27 -0700227 if (progress == nullptr)
228 {
229 return !task::completed;
230 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000231 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700232 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000233 messages::taskProgressChanged(index,
234 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700235
Ed Tanous002d39b2022-05-31 08:59:27 -0700236 // if we're getting status updates it's
237 // still alive, update timer
238 taskData->extendTimer(std::chrono::minutes(5));
239 }
240
241 // as firmware update often results in a
242 // reboot, the task may never "complete"
243 // unless it is an error
244
245 return !task::completed;
246 },
247 "type='signal',interface='org.freedesktop.DBus.Properties',"
248 "member='PropertiesChanged',path='" +
249 objPath.str + "'");
250 task->startTimer(std::chrono::minutes(5));
251 task->populateResp(asyncResp->res);
252 task->payload.emplace(std::move(payload));
253 }
254 fwUpdateInProgress = false;
George Liu2b731192023-01-11 16:27:13 +0800255 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500256
257 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500258 }
259 }
260}
261
Andrew Geissler0554c982019-04-23 14:40:12 -0500262// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
263// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700264static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800265 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
266 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500267 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500268{
269 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800270 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500271 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500272 if (asyncResp)
273 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500274 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
275 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276 return;
277 }
278
Andrew Geissler0554c982019-04-23 14:40:12 -0500279 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700280 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500281
Ed Tanous271584a2019-07-09 16:24:22 -0700282 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500283
284 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500285 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700286 cleanUp();
287 if (ec == boost::asio::error::operation_aborted)
288 {
289 // expected, we were canceled before the timer completed.
290 return;
291 }
292 BMCWEB_LOG_ERROR
293 << "Timed out waiting for firmware object being created";
294 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
295 if (ec)
296 {
297 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
298 return;
299 }
300 if (asyncResp)
301 {
302 redfish::messages::internalError(asyncResp->res);
303 }
304 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700305 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500306 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500307 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700308 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500309 };
310
311 fwUpdateInProgress = true;
312
Patrick Williams59d494e2022-07-22 19:26:55 -0500313 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500314 *crow::connections::systemBus,
315 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
316 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
317 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700318
Patrick Williams59d494e2022-07-22 19:26:55 -0500319 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700320 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800321 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
322 "member='InterfacesAdded',"
323 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500324 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
326 interfacesProperties;
327 sdbusplus::message::object_path objPath;
328 m.read(objPath, interfacesProperties);
329 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
330 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
331 interface : interfacesProperties)
332 {
333 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 for (const std::pair<std::string,
336 dbus::utility::DbusVariantType>& value :
337 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800338 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700339 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800340 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700341 continue;
342 }
343 const std::string* type =
344 std::get_if<std::string>(&value.second);
345 if (type == nullptr)
346 {
347 // if this was our message, timeout will cover it
348 return;
349 }
350 fwAvailableTimer = nullptr;
351 if (*type ==
352 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
353 {
354 redfish::messages::invalidUpload(asyncResp->res, url,
355 "Invalid archive");
356 }
357 else if (*type ==
358 "xyz.openbmc_project.Software.Image.Error."
359 "ManifestFileFailure")
360 {
361 redfish::messages::invalidUpload(asyncResp->res, url,
362 "Invalid manifest");
363 }
364 else if (
365 *type ==
366 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
367 {
368 redfish::messages::invalidUpload(
369 asyncResp->res, url, "Invalid image format");
370 }
371 else if (
372 *type ==
373 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
374 {
375 redfish::messages::invalidUpload(
376 asyncResp->res, url,
377 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600378
Ed Tanous002d39b2022-05-31 08:59:27 -0700379 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800380 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700381 "uploaded version");
382 }
383 else if (
384 *type ==
385 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
386 {
387 redfish::messages::resourceExhaustion(asyncResp->res,
388 url);
389 }
390 else
391 {
392 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800393 }
394 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600395 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 }
James Feist4cde5d92020-06-11 10:39:55 -0700397 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500398}
Jennifer Lee729dae72018-04-24 15:59:34 -0700399
Andrew Geissler0554c982019-04-23 14:40:12 -0500400/**
401 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
402 * SimpleUpdate action.
403 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700404inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500405{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700406 BMCWEB_ROUTE(
407 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700408 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 .methods(boost::beast::http::verb::post)(
410 [&app](const crow::Request& req,
411 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000412 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 {
414 return;
415 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700416
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 std::optional<std::string> transferProtocol;
418 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500419
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500421
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 // User can pass in both TransferProtocol and ImageURI parameters or
423 // they can pass in just the ImageURI with the transfer protocol
424 // embedded within it.
425 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
426 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500427
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
429 transferProtocol, "ImageURI", imageURI))
430 {
431 BMCWEB_LOG_DEBUG
432 << "Missing TransferProtocol or ImageURI parameter";
433 return;
434 }
435 if (!transferProtocol)
436 {
437 // Must be option 2
438 // Verify ImageURI has transfer protocol in it
439 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500440 if ((separator == std::string::npos) ||
441 ((separator + 1) > imageURI.size()))
442 {
443 messages::actionParameterValueTypeError(
444 asyncResp->res, imageURI, "ImageURI",
445 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700446 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
447 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530448 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530449 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 transferProtocol = imageURI.substr(0, separator);
451 // Ensure protocol is upper case for a common comparison path
452 // below
453 boost::to_upper(*transferProtocol);
454 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
455 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530456
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 // Adjust imageURI to not have the protocol on it for parsing
458 // below
459 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
460 imageURI = imageURI.substr(separator + 3);
461 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
462 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530463
Ed Tanous002d39b2022-05-31 08:59:27 -0700464 // OpenBMC currently only supports TFTP
465 if (*transferProtocol != "TFTP")
466 {
467 messages::actionParameterNotSupported(asyncResp->res,
468 "TransferProtocol",
469 "UpdateService.SimpleUpdate");
470 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
471 << *transferProtocol;
472 return;
473 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700474
Ed Tanous002d39b2022-05-31 08:59:27 -0700475 // Format should be <IP or Hostname>/<file> for imageURI
476 size_t separator = imageURI.find('/');
477 if ((separator == std::string::npos) ||
478 ((separator + 1) > imageURI.size()))
479 {
480 messages::actionParameterValueTypeError(
481 asyncResp->res, imageURI, "ImageURI",
482 "UpdateService.SimpleUpdate");
483 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
484 return;
485 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700486
Ed Tanous002d39b2022-05-31 08:59:27 -0700487 std::string tftpServer = imageURI.substr(0, separator);
488 std::string fwFile = imageURI.substr(separator + 1);
489 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700490
Ed Tanous002d39b2022-05-31 08:59:27 -0700491 // Setup callback for when new software detected
492 // Give TFTP 10 minutes to complete
493 monitorForSoftwareAvailable(
494 asyncResp, req,
495 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
496 600);
497
498 // TFTP can take up to 10 minutes depending on image size and
499 // connection speed. Return to caller as soon as the TFTP operation
500 // has been started. The callback above will ensure the activate
501 // is started once the download has completed
502 redfish::messages::success(asyncResp->res);
503
504 // Call TFTP service
505 crow::connections::systemBus->async_method_call(
506 [](const boost::system::error_code ec) {
507 if (ec)
508 {
509 // messages::internalError(asyncResp->res);
510 cleanUp();
511 BMCWEB_LOG_DEBUG << "error_code = " << ec;
512 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
513 }
514 else
515 {
516 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
517 }
518 },
519 "xyz.openbmc_project.Software.Download",
520 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
521 "DownloadViaTFTP", fwFile, tftpServer);
522
523 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700524 });
525}
526
Ed Tanousc2051d12022-05-11 12:21:55 -0700527inline void
528 handleUpdateServicePost(App& app, const crow::Request& req,
529 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
530{
Carson Labrado3ba00072022-06-06 19:40:56 +0000531 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700532 {
533 return;
534 }
535 BMCWEB_LOG_DEBUG << "doPost...";
536
537 // Setup callback for when new software detected
538 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
539
540 std::string filepath(
541 "/tmp/images/" +
542 boost::uuids::to_string(boost::uuids::random_generator()()));
543 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
544 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
545 std::ofstream::trunc);
546 out << req.body;
547 out.close();
548 BMCWEB_LOG_DEBUG << "file upload complete!!";
549}
550
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700551inline void requestRoutesUpdateService(App& app)
552{
553 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700554 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700555 .methods(boost::beast::http::verb::get)(
556 [&app](const crow::Request& req,
557 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000558 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700559 {
560 return;
561 }
562 asyncResp->res.jsonValue["@odata.type"] =
563 "#UpdateService.v1_5_0.UpdateService";
564 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
565 asyncResp->res.jsonValue["Id"] = "UpdateService";
566 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
567 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700568
Ed Tanous32ca38a2022-05-11 12:36:59 -0700569#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700570 // See note about later on in this file about why this is neccesary
571 // This is "Wrong" per the standard, but is done temporarily to
572 // avoid noise in failing tests as people transition to having this
573 // option disabled
574 asyncResp->res.addHeader(boost::beast::http::field::allow,
575 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700576#endif
577
Ed Tanous002d39b2022-05-31 08:59:27 -0700578 asyncResp->res.jsonValue["HttpPushUri"] =
579 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700580
Ed Tanous002d39b2022-05-31 08:59:27 -0700581 // UpdateService cannot be disabled
582 asyncResp->res.jsonValue["ServiceEnabled"] = true;
583 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
584 "/redfish/v1/UpdateService/FirmwareInventory";
585 // Get the MaxImageSizeBytes
586 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
587 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530588
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700589#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700590 // Update Actions object.
591 nlohmann::json& updateSvcSimpleUpdate =
592 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
593 updateSvcSimpleUpdate["target"] =
594 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
595 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
596 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700597#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700598 // Get the current ApplyTime value
599 sdbusplus::asio::getProperty<std::string>(
600 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
601 "/xyz/openbmc_project/software/apply_time",
602 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
603 [asyncResp](const boost::system::error_code ec,
604 const std::string& applyTime) {
605 if (ec)
606 {
607 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
608 messages::internalError(asyncResp->res);
609 return;
610 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530611
Ed Tanous002d39b2022-05-31 08:59:27 -0700612 // Store the ApplyTime Value
613 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
614 "RequestedApplyTimes.Immediate")
615 {
616 asyncResp->res.jsonValue["HttpPushUriOptions"]
617 ["HttpPushUriApplyTime"]["ApplyTime"] =
618 "Immediate";
619 }
620 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
621 "RequestedApplyTimes.OnReset")
622 {
623 asyncResp->res.jsonValue["HttpPushUriOptions"]
624 ["HttpPushUriApplyTime"]["ApplyTime"] =
625 "OnReset";
626 }
627 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700628 });
629 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700630 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700631 .methods(boost::beast::http::verb::patch)(
632 [&app](const crow::Request& req,
633 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000634 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700635 {
636 return;
637 }
638 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530639
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 std::optional<nlohmann::json> pushUriOptions;
641 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
642 pushUriOptions))
643 {
644 return;
645 }
646
647 if (pushUriOptions)
648 {
649 std::optional<nlohmann::json> pushUriApplyTime;
650 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
651 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800652 {
653 return;
654 }
655
Ed Tanous002d39b2022-05-31 08:59:27 -0700656 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800657 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700658 std::optional<std::string> applyTime;
659 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
660 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700662 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700664
Ed Tanous002d39b2022-05-31 08:59:27 -0700665 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700667 std::string applyTimeNewVal;
668 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700669 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700670 applyTimeNewVal =
671 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
672 }
673 else if (applyTime == "OnReset")
674 {
675 applyTimeNewVal =
676 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
677 }
678 else
679 {
680 BMCWEB_LOG_INFO
681 << "ApplyTime value is not in the list of acceptable values";
682 messages::propertyValueNotInList(
683 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700684 return;
685 }
686
Ed Tanous002d39b2022-05-31 08:59:27 -0700687 // Set the requested image apply time value
688 crow::connections::systemBus->async_method_call(
689 [asyncResp](const boost::system::error_code ec) {
690 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700691 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
693 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700694 return;
695 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700696 messages::success(asyncResp->res);
697 },
698 "xyz.openbmc_project.Settings",
699 "/xyz/openbmc_project/software/apply_time",
700 "org.freedesktop.DBus.Properties", "Set",
701 "xyz.openbmc_project.Software.ApplyTime",
702 "RequestedApplyTime",
703 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700704 }
George Liu0fda0f12021-11-16 10:06:17 +0800705 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700706 }
George Liu0fda0f12021-11-16 10:06:17 +0800707 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700708
Ed Tanous4dc23f32022-05-11 11:32:19 -0700709// The "old" behavior of the update service URI causes redfish-service validator
710// failures when the Allow header is supported, given that in the spec,
711// UpdateService does not allow POST. in openbmc, we unfortunately reused that
712// resource as our HttpPushUri as well. A number of services, including the
713// openbmc tests, and documentation have hardcoded that erroneous API, instead
714// of relying on HttpPushUri as the spec requires. This option will exist
715// temporarily to allow the old behavior until Q4 2022, at which time it will be
716// removed.
717#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700718 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700719 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700720 .methods(boost::beast::http::verb::post)(
721 [&app](const crow::Request& req,
722 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
723 asyncResp->res.addHeader(
724 boost::beast::http::field::warning,
725 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
726 "the value contained within HttpPushUri.\"");
727 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700728 });
729#endif
730 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
731 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700732 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700733 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700734}
735
736inline void requestRoutesSoftwareInventoryCollection(App& app)
737{
738 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700739 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700740 .methods(boost::beast::http::verb::get)(
741 [&app](const crow::Request& req,
742 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000743 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700744 {
745 return;
746 }
747 asyncResp->res.jsonValue["@odata.type"] =
748 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
749 asyncResp->res.jsonValue["@odata.id"] =
750 "/redfish/v1/UpdateService/FirmwareInventory";
751 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
752
753 crow::connections::systemBus->async_method_call(
754 [asyncResp](
755 const boost::system::error_code ec,
756 const dbus::utility::MapperGetSubTreeResponse& subtree) {
757 if (ec)
758 {
759 messages::internalError(asyncResp->res);
760 return;
761 }
762 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
763 asyncResp->res.jsonValue["Members@odata.count"] = 0;
764
765 for (const auto& obj : subtree)
766 {
767 sdbusplus::message::object_path path(obj.first);
768 std::string swId = path.filename();
769 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700770 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700771 messages::internalError(asyncResp->res);
772 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700773 return;
774 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700775
Ed Tanous002d39b2022-05-31 08:59:27 -0700776 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
777 nlohmann::json::object_t member;
778 member["@odata.id"] =
779 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
780 members.push_back(std::move(member));
781 asyncResp->res.jsonValue["Members@odata.count"] =
782 members.size();
783 }
784 },
785 // Note that only firmware levels associated with a device
786 // are stored under /xyz/openbmc_project/software therefore
787 // to ensure only real FirmwareInventory items are returned,
788 // this full object path must be used here as input to
789 // mapper
790 "xyz.openbmc_project.ObjectMapper",
791 "/xyz/openbmc_project/object_mapper",
792 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
793 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
794 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
795 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700796}
797/* Fill related item links (i.e. bmc, bios) in for inventory */
798inline static void
799 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
800 const std::string& purpose)
801{
Willy Tueee00132022-06-14 14:53:17 -0700802 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700803 {
804 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700805 nlohmann::json::object_t item;
806 item["@odata.id"] = "/redfish/v1/Managers/bmc";
807 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700808 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
809 }
Willy Tueee00132022-06-14 14:53:17 -0700810 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700811 {
812 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700813 nlohmann::json::object_t item;
814 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
815 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800816 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700817 }
818 else
819 {
820 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
821 }
822}
823
Willy Tuaf246602022-06-14 15:51:53 -0700824inline void
825 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
826 const std::string& service, const std::string& path,
827 const std::string& swId)
828{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200829 sdbusplus::asio::getAllProperties(
830 *crow::connections::systemBus, service, path,
831 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700832 [asyncResp,
833 swId](const boost::system::error_code errorCode,
834 const dbus::utility::DBusPropertiesMap& propertiesList) {
835 if (errorCode)
836 {
837 messages::internalError(asyncResp->res);
838 return;
839 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200840
Willy Tuaf246602022-06-14 15:51:53 -0700841 const std::string* swInvPurpose = nullptr;
842 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200843
844 const bool success = sdbusplus::unpackPropertiesNoThrow(
845 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
846 swInvPurpose, "Version", version);
847
848 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700849 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200850 messages::internalError(asyncResp->res);
851 return;
Willy Tuaf246602022-06-14 15:51:53 -0700852 }
853
854 if (swInvPurpose == nullptr)
855 {
856 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
857 messages::internalError(asyncResp->res);
858 return;
859 }
860
861 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
862
863 if (version == nullptr)
864 {
865 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
866
867 messages::internalError(asyncResp->res);
868
869 return;
870 }
871 asyncResp->res.jsonValue["Version"] = *version;
872 asyncResp->res.jsonValue["Id"] = swId;
873
874 // swInvPurpose is of format:
875 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
876 // Translate this to "ABC image"
877 size_t endDesc = swInvPurpose->rfind('.');
878 if (endDesc == std::string::npos)
879 {
880 messages::internalError(asyncResp->res);
881 return;
882 }
883 endDesc++;
884 if (endDesc >= swInvPurpose->size())
885 {
886 messages::internalError(asyncResp->res);
887 return;
888 }
889
890 std::string formatDesc = swInvPurpose->substr(endDesc);
891 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
892 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200893 });
Willy Tuaf246602022-06-14 15:51:53 -0700894}
895
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700896inline void requestRoutesSoftwareInventory(App& app)
897{
898 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700899 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700900 .methods(boost::beast::http::verb::get)(
901 [&app](const crow::Request& req,
902 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
903 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000904 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700905 {
906 return;
907 }
908 std::shared_ptr<std::string> swId =
909 std::make_shared<std::string>(param);
910
911 asyncResp->res.jsonValue["@odata.id"] =
912 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
913
914 crow::connections::systemBus->async_method_call(
915 [asyncResp,
916 swId](const boost::system::error_code ec,
917 const dbus::utility::MapperGetSubTreeResponse& subtree) {
918 BMCWEB_LOG_DEBUG << "doGet callback...";
919 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700920 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700921 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700922 return;
923 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700924
Ed Tanous002d39b2022-05-31 08:59:27 -0700925 // Ensure we find our input swId, otherwise return an error
926 bool found = false;
927 for (const std::pair<std::string,
928 std::vector<std::pair<
929 std::string, std::vector<std::string>>>>&
930 obj : subtree)
931 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700932 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700933 {
934 continue;
935 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700936
Ed Tanous002d39b2022-05-31 08:59:27 -0700937 if (obj.second.empty())
938 {
939 continue;
940 }
941
942 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700943 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700944 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
945 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700946 }
947 if (!found)
948 {
949 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
950 messages::resourceMissingAtURI(
951 asyncResp->res, crow::utility::urlFromPieces(
952 "redfish", "v1", "UpdateService",
953 "FirmwareInventory", *swId));
954 return;
955 }
956 asyncResp->res.jsonValue["@odata.type"] =
957 "#SoftwareInventory.v1_1_0.SoftwareInventory";
958 asyncResp->res.jsonValue["Name"] = "Software Inventory";
959 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700960
Ed Tanous002d39b2022-05-31 08:59:27 -0700961 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700962 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700963 },
964 "xyz.openbmc_project.ObjectMapper",
965 "/xyz/openbmc_project/object_mapper",
966 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
967 static_cast<int32_t>(0),
968 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700969 });
970}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971
972} // namespace redfish