blob: 041e0726cdbff17b588a855eb67ac8fdc43a0821 [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"
Ed Tanousa8e884f2023-01-13 17:40:03 -080024#include "task.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "utils/dbus_utils.hpp"
26#include "utils/sw_utils.hpp"
27
George Liue99073f2022-12-09 11:06:16 +080028#include <boost/system/error_code.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070029#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080030#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020031#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032
George Liu2b731192023-01-11 16:27:13 +080033#include <array>
34#include <string_view>
35
Ed Tanous1abe55e2018-09-05 08:30:59 -070036namespace redfish
37{
Ed Tanous27826b52018-10-29 11:40:58 -070038
Andrew Geissler0e7de462019-03-04 19:11:54 -060039// Match signals added on software path
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> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080042// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050043static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060044// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080045// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060046static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050047// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080048// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070049static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050050
John Edward Broadbent7e860f12021-04-08 15:57:16 -070051inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050052{
53 fwUpdateInProgress = false;
54 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070055 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050056}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070057inline static void activateImage(const std::string& objPath,
58 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050059{
60 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
61 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000062 [](const boost::system::error_code errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070063 if (errorCode)
64 {
65 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
66 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
67 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050068 },
69 service, objPath, "org.freedesktop.DBus.Properties", "Set",
70 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080071 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080072 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050073}
Andrew Geissler0554c982019-04-23 14:40:12 -050074
75// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
76// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080077static void
78 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050079 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050080{
Ed Tanousb9d36b42022-02-26 21:42:46 -080081 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050082
83 sdbusplus::message::object_path objPath;
84
85 m.read(objPath, interfacesProperties);
86
87 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Ed Tanouse3eb3d62022-12-21 11:56:07 -080088 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050089 {
90 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
91
92 if (interface.first == "xyz.openbmc_project.Software.Activation")
93 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050094 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +080095 constexpr std::array<std::string_view, 1> interfaces = {
96 "xyz.openbmc_project.Software.Activation"};
97 dbus::utility::getDbusObject(
98 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -070099 [objPath, asyncResp, payload(std::move(payload))](
George Liu2b731192023-01-11 16:27:13 +0800100 const boost::system::error_code& errorCode,
Ed Tanousa3e65892021-09-16 14:13:20 -0700101 const std::vector<
102 std::pair<std::string, std::vector<std::string>>>&
103 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700104 if (errorCode)
105 {
106 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
107 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -0500108 if (asyncResp)
109 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700110 messages::internalError(asyncResp->res);
111 }
112 cleanUp();
113 return;
114 }
115 // Ensure we only got one service back
116 if (objInfo.size() != 1)
117 {
118 BMCWEB_LOG_ERROR << "Invalid Object Size "
119 << objInfo.size();
120 if (asyncResp)
121 {
122 messages::internalError(asyncResp->res);
123 }
124 cleanUp();
125 return;
126 }
127 // cancel timer only when
128 // xyz.openbmc_project.Software.Activation interface
129 // is added
130 fwAvailableTimer = nullptr;
131
132 activateImage(objPath.str, objInfo[0].first);
133 if (asyncResp)
134 {
135 std::shared_ptr<task::TaskData> task =
136 task::TaskData::createTask(
137 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500138 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700139 const std::shared_ptr<task::TaskData>&
140 taskData) {
141 if (ec)
142 {
143 return task::completed;
144 }
145
146 std::string iface;
147 dbus::utility::DBusPropertiesMap values;
148
149 std::string index = std::to_string(taskData->index);
150 msg.read(iface, values);
151
152 if (iface == "xyz.openbmc_project.Software.Activation")
153 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000154 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 for (const auto& property : values)
156 {
157 if (property.first == "Activation")
158 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000159 state = std::get_if<std::string>(
160 &property.second);
161 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700162 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 taskData->messages.emplace_back(
164 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700165 return task::completed;
166 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700167 }
168 }
James Feist32898ce2020-03-10 16:16:52 -0700169
Ed Tanous002d39b2022-05-31 08:59:27 -0700170 if (state == nullptr)
171 {
172 return !task::completed;
173 }
James Feist32898ce2020-03-10 16:16:52 -0700174
Ed Tanous11ba3972022-07-11 09:50:41 -0700175 if (state->ends_with("Invalid") ||
176 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700177 {
178 taskData->state = "Exception";
179 taskData->status = "Warning";
180 taskData->messages.emplace_back(
181 messages::taskAborted(index));
182 return task::completed;
183 }
James Feiste5d50062020-05-11 17:29:00 -0700184
Ed Tanous11ba3972022-07-11 09:50:41 -0700185 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700186 {
187 taskData->state = "Stopping";
188 taskData->messages.emplace_back(
189 messages::taskPaused(index));
190
191 // its staged, set a long timer to
192 // allow them time to complete the
193 // update (probably cycle the
194 // system) if this expires then
195 // task will be cancelled
196 taskData->extendTimer(std::chrono::hours(5));
197 return !task::completed;
198 }
199
Ed Tanous11ba3972022-07-11 09:50:41 -0700200 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 {
202 taskData->messages.emplace_back(
203 messages::taskCompletedOK(index));
204 taskData->state = "Completed";
205 return task::completed;
206 }
207 }
208 else if (
209 iface ==
210 "xyz.openbmc_project.Software.ActivationProgress")
211 {
212
213 const uint8_t* progress = nullptr;
214 for (const auto& property : values)
215 {
216 if (property.first == "Progress")
217 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000218 progress =
219 std::get_if<uint8_t>(&property.second);
220 if (progress == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700221 {
James Feist32898ce2020-03-10 16:16:52 -0700222 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700223 messages::internalError());
224 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700225 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700226 }
227 }
James Feist32898ce2020-03-10 16:16:52 -0700228
Ed Tanous002d39b2022-05-31 08:59:27 -0700229 if (progress == nullptr)
230 {
231 return !task::completed;
232 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000233 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700234 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000235 messages::taskProgressChanged(index,
236 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700237
Ed Tanous002d39b2022-05-31 08:59:27 -0700238 // if we're getting status updates it's
239 // still alive, update timer
240 taskData->extendTimer(std::chrono::minutes(5));
241 }
242
243 // as firmware update often results in a
244 // reboot, the task may never "complete"
245 // unless it is an error
246
247 return !task::completed;
248 },
249 "type='signal',interface='org.freedesktop.DBus.Properties',"
250 "member='PropertiesChanged',path='" +
251 objPath.str + "'");
252 task->startTimer(std::chrono::minutes(5));
253 task->populateResp(asyncResp->res);
254 task->payload.emplace(std::move(payload));
255 }
256 fwUpdateInProgress = false;
George Liu2b731192023-01-11 16:27:13 +0800257 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500258
259 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500260 }
261 }
262}
263
Andrew Geissler0554c982019-04-23 14:40:12 -0500264// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
265// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700266static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800267 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
268 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500269 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500270{
271 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800272 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500273 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500274 if (asyncResp)
275 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500276 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
277 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500278 return;
279 }
280
Andrew Geissler0554c982019-04-23 14:40:12 -0500281 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700282 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500283
Ed Tanous271584a2019-07-09 16:24:22 -0700284 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500285
286 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500287 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 cleanUp();
289 if (ec == boost::asio::error::operation_aborted)
290 {
291 // expected, we were canceled before the timer completed.
292 return;
293 }
294 BMCWEB_LOG_ERROR
295 << "Timed out waiting for firmware object being created";
296 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
297 if (ec)
298 {
299 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
300 return;
301 }
302 if (asyncResp)
303 {
304 redfish::messages::internalError(asyncResp->res);
305 }
306 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700307 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500308 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500309 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700310 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500311 };
312
313 fwUpdateInProgress = true;
314
Patrick Williams59d494e2022-07-22 19:26:55 -0500315 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500316 *crow::connections::systemBus,
317 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
318 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
319 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700320
Patrick Williams59d494e2022-07-22 19:26:55 -0500321 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700322 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800323 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
324 "member='InterfacesAdded',"
325 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500326 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
328 interfacesProperties;
329 sdbusplus::message::object_path objPath;
330 m.read(objPath, interfacesProperties);
331 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
332 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
333 interface : interfacesProperties)
334 {
335 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700336 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700337 for (const std::pair<std::string,
338 dbus::utility::DbusVariantType>& value :
339 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800340 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700341 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800342 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700343 continue;
344 }
345 const std::string* type =
346 std::get_if<std::string>(&value.second);
347 if (type == nullptr)
348 {
349 // if this was our message, timeout will cover it
350 return;
351 }
352 fwAvailableTimer = nullptr;
353 if (*type ==
354 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
355 {
356 redfish::messages::invalidUpload(asyncResp->res, url,
357 "Invalid archive");
358 }
359 else if (*type ==
360 "xyz.openbmc_project.Software.Image.Error."
361 "ManifestFileFailure")
362 {
363 redfish::messages::invalidUpload(asyncResp->res, url,
364 "Invalid manifest");
365 }
366 else if (
367 *type ==
368 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
369 {
370 redfish::messages::invalidUpload(
371 asyncResp->res, url, "Invalid image format");
372 }
373 else if (
374 *type ==
375 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
376 {
377 redfish::messages::invalidUpload(
378 asyncResp->res, url,
379 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600380
Ed Tanous002d39b2022-05-31 08:59:27 -0700381 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800382 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 "uploaded version");
384 }
385 else if (
386 *type ==
387 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
388 {
389 redfish::messages::resourceExhaustion(asyncResp->res,
390 url);
391 }
392 else
393 {
394 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800395 }
396 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600397 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700398 }
James Feist4cde5d92020-06-11 10:39:55 -0700399 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500400}
Jennifer Lee729dae72018-04-24 15:59:34 -0700401
Andrew Geissler0554c982019-04-23 14:40:12 -0500402/**
403 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
404 * SimpleUpdate action.
405 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700406inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500407{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700408 BMCWEB_ROUTE(
409 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700410 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700411 .methods(boost::beast::http::verb::post)(
412 [&app](const crow::Request& req,
413 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000414 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700415 {
416 return;
417 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700418
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 std::optional<std::string> transferProtocol;
420 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500421
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500423
Ed Tanous002d39b2022-05-31 08:59:27 -0700424 // User can pass in both TransferProtocol and ImageURI parameters or
425 // they can pass in just the ImageURI with the transfer protocol
426 // embedded within it.
427 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
428 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500429
Ed Tanous002d39b2022-05-31 08:59:27 -0700430 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
431 transferProtocol, "ImageURI", imageURI))
432 {
433 BMCWEB_LOG_DEBUG
434 << "Missing TransferProtocol or ImageURI parameter";
435 return;
436 }
437 if (!transferProtocol)
438 {
439 // Must be option 2
440 // Verify ImageURI has transfer protocol in it
441 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500442 if ((separator == std::string::npos) ||
443 ((separator + 1) > imageURI.size()))
444 {
445 messages::actionParameterValueTypeError(
446 asyncResp->res, imageURI, "ImageURI",
447 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
449 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530450 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530451 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 transferProtocol = imageURI.substr(0, separator);
453 // Ensure protocol is upper case for a common comparison path
454 // below
455 boost::to_upper(*transferProtocol);
456 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
457 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530458
Ed Tanous002d39b2022-05-31 08:59:27 -0700459 // Adjust imageURI to not have the protocol on it for parsing
460 // below
461 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
462 imageURI = imageURI.substr(separator + 3);
463 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
464 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530465
Ed Tanous002d39b2022-05-31 08:59:27 -0700466 // OpenBMC currently only supports TFTP
467 if (*transferProtocol != "TFTP")
468 {
469 messages::actionParameterNotSupported(asyncResp->res,
470 "TransferProtocol",
471 "UpdateService.SimpleUpdate");
472 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
473 << *transferProtocol;
474 return;
475 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700476
Ed Tanous002d39b2022-05-31 08:59:27 -0700477 // Format should be <IP or Hostname>/<file> for imageURI
478 size_t separator = imageURI.find('/');
479 if ((separator == std::string::npos) ||
480 ((separator + 1) > imageURI.size()))
481 {
482 messages::actionParameterValueTypeError(
483 asyncResp->res, imageURI, "ImageURI",
484 "UpdateService.SimpleUpdate");
485 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
486 return;
487 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700488
Ed Tanous002d39b2022-05-31 08:59:27 -0700489 std::string tftpServer = imageURI.substr(0, separator);
490 std::string fwFile = imageURI.substr(separator + 1);
491 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 // Setup callback for when new software detected
494 // Give TFTP 10 minutes to complete
495 monitorForSoftwareAvailable(
496 asyncResp, req,
497 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
498 600);
499
500 // TFTP can take up to 10 minutes depending on image size and
501 // connection speed. Return to caller as soon as the TFTP operation
502 // has been started. The callback above will ensure the activate
503 // is started once the download has completed
504 redfish::messages::success(asyncResp->res);
505
506 // Call TFTP service
507 crow::connections::systemBus->async_method_call(
508 [](const boost::system::error_code ec) {
509 if (ec)
510 {
511 // messages::internalError(asyncResp->res);
512 cleanUp();
513 BMCWEB_LOG_DEBUG << "error_code = " << ec;
514 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
515 }
516 else
517 {
518 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
519 }
520 },
521 "xyz.openbmc_project.Software.Download",
522 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
523 "DownloadViaTFTP", fwFile, tftpServer);
524
525 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700526 });
527}
528
Ed Tanousc2051d12022-05-11 12:21:55 -0700529inline void
530 handleUpdateServicePost(App& app, const crow::Request& req,
531 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
532{
Carson Labrado3ba00072022-06-06 19:40:56 +0000533 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700534 {
535 return;
536 }
537 BMCWEB_LOG_DEBUG << "doPost...";
538
539 // Setup callback for when new software detected
540 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
541
542 std::string filepath(
543 "/tmp/images/" +
544 boost::uuids::to_string(boost::uuids::random_generator()()));
545 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
546 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
547 std::ofstream::trunc);
548 out << req.body;
549 out.close();
550 BMCWEB_LOG_DEBUG << "file upload complete!!";
551}
552
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700553inline void requestRoutesUpdateService(App& app)
554{
555 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700556 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700557 .methods(boost::beast::http::verb::get)(
558 [&app](const crow::Request& req,
559 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000560 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700561 {
562 return;
563 }
564 asyncResp->res.jsonValue["@odata.type"] =
565 "#UpdateService.v1_5_0.UpdateService";
566 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
567 asyncResp->res.jsonValue["Id"] = "UpdateService";
568 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
569 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700570
Ed Tanous32ca38a2022-05-11 12:36:59 -0700571#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700572 // See note about later on in this file about why this is neccesary
573 // This is "Wrong" per the standard, but is done temporarily to
574 // avoid noise in failing tests as people transition to having this
575 // option disabled
576 asyncResp->res.addHeader(boost::beast::http::field::allow,
577 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700578#endif
579
Ed Tanous002d39b2022-05-31 08:59:27 -0700580 asyncResp->res.jsonValue["HttpPushUri"] =
581 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700582
Ed Tanous002d39b2022-05-31 08:59:27 -0700583 // UpdateService cannot be disabled
584 asyncResp->res.jsonValue["ServiceEnabled"] = true;
585 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
586 "/redfish/v1/UpdateService/FirmwareInventory";
587 // Get the MaxImageSizeBytes
588 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
589 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530590
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700591#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 // Update Actions object.
593 nlohmann::json& updateSvcSimpleUpdate =
594 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
595 updateSvcSimpleUpdate["target"] =
596 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
597 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
598 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700599#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700600 // Get the current ApplyTime value
601 sdbusplus::asio::getProperty<std::string>(
602 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
603 "/xyz/openbmc_project/software/apply_time",
604 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
605 [asyncResp](const boost::system::error_code ec,
606 const std::string& applyTime) {
607 if (ec)
608 {
609 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
610 messages::internalError(asyncResp->res);
611 return;
612 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530613
Ed Tanous002d39b2022-05-31 08:59:27 -0700614 // Store the ApplyTime Value
615 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
616 "RequestedApplyTimes.Immediate")
617 {
618 asyncResp->res.jsonValue["HttpPushUriOptions"]
619 ["HttpPushUriApplyTime"]["ApplyTime"] =
620 "Immediate";
621 }
622 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
623 "RequestedApplyTimes.OnReset")
624 {
625 asyncResp->res.jsonValue["HttpPushUriOptions"]
626 ["HttpPushUriApplyTime"]["ApplyTime"] =
627 "OnReset";
628 }
629 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700630 });
631 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700632 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 .methods(boost::beast::http::verb::patch)(
634 [&app](const crow::Request& req,
635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000636 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700637 {
638 return;
639 }
640 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530641
Ed Tanous002d39b2022-05-31 08:59:27 -0700642 std::optional<nlohmann::json> pushUriOptions;
643 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
644 pushUriOptions))
645 {
646 return;
647 }
648
649 if (pushUriOptions)
650 {
651 std::optional<nlohmann::json> pushUriApplyTime;
652 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
653 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800654 {
655 return;
656 }
657
Ed Tanous002d39b2022-05-31 08:59:27 -0700658 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800659 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700660 std::optional<std::string> applyTime;
661 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
662 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700664 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700666
Ed Tanous002d39b2022-05-31 08:59:27 -0700667 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700669 std::string applyTimeNewVal;
670 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700671 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700672 applyTimeNewVal =
673 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
674 }
675 else if (applyTime == "OnReset")
676 {
677 applyTimeNewVal =
678 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
679 }
680 else
681 {
682 BMCWEB_LOG_INFO
683 << "ApplyTime value is not in the list of acceptable values";
684 messages::propertyValueNotInList(
685 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700686 return;
687 }
688
Ed Tanous002d39b2022-05-31 08:59:27 -0700689 // Set the requested image apply time value
690 crow::connections::systemBus->async_method_call(
691 [asyncResp](const boost::system::error_code ec) {
692 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700693 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700694 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
695 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700696 return;
697 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700698 messages::success(asyncResp->res);
699 },
700 "xyz.openbmc_project.Settings",
701 "/xyz/openbmc_project/software/apply_time",
702 "org.freedesktop.DBus.Properties", "Set",
703 "xyz.openbmc_project.Software.ApplyTime",
704 "RequestedApplyTime",
705 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700706 }
George Liu0fda0f12021-11-16 10:06:17 +0800707 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700708 }
George Liu0fda0f12021-11-16 10:06:17 +0800709 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700710
Ed Tanous4dc23f32022-05-11 11:32:19 -0700711// The "old" behavior of the update service URI causes redfish-service validator
712// failures when the Allow header is supported, given that in the spec,
713// UpdateService does not allow POST. in openbmc, we unfortunately reused that
714// resource as our HttpPushUri as well. A number of services, including the
715// openbmc tests, and documentation have hardcoded that erroneous API, instead
716// of relying on HttpPushUri as the spec requires. This option will exist
717// temporarily to allow the old behavior until Q4 2022, at which time it will be
718// removed.
719#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700720 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700721 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700722 .methods(boost::beast::http::verb::post)(
723 [&app](const crow::Request& req,
724 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
725 asyncResp->res.addHeader(
726 boost::beast::http::field::warning,
727 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
728 "the value contained within HttpPushUri.\"");
729 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700730 });
731#endif
732 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
733 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700734 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700735 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700736}
737
738inline void requestRoutesSoftwareInventoryCollection(App& app)
739{
740 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700741 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700742 .methods(boost::beast::http::verb::get)(
743 [&app](const crow::Request& req,
744 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000745 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700746 {
747 return;
748 }
749 asyncResp->res.jsonValue["@odata.type"] =
750 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
751 asyncResp->res.jsonValue["@odata.id"] =
752 "/redfish/v1/UpdateService/FirmwareInventory";
753 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
754
George Liue99073f2022-12-09 11:06:16 +0800755 // Note that only firmware levels associated with a device
756 // are stored under /xyz/openbmc_project/software therefore
757 // to ensure only real FirmwareInventory items are returned,
758 // this full object path must be used here as input to
759 // mapper
760 constexpr std::array<std::string_view, 1> interfaces = {
761 "xyz.openbmc_project.Software.Version"};
762 dbus::utility::getSubTree(
763 "/xyz/openbmc_project/software", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700764 [asyncResp](
George Liue99073f2022-12-09 11:06:16 +0800765 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700766 const dbus::utility::MapperGetSubTreeResponse& subtree) {
767 if (ec)
768 {
769 messages::internalError(asyncResp->res);
770 return;
771 }
772 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
773 asyncResp->res.jsonValue["Members@odata.count"] = 0;
774
775 for (const auto& obj : subtree)
776 {
777 sdbusplus::message::object_path path(obj.first);
778 std::string swId = path.filename();
779 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700780 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700781 messages::internalError(asyncResp->res);
782 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700783 return;
784 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700785
Ed Tanous002d39b2022-05-31 08:59:27 -0700786 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
787 nlohmann::json::object_t member;
788 member["@odata.id"] =
789 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
790 members.push_back(std::move(member));
791 asyncResp->res.jsonValue["Members@odata.count"] =
792 members.size();
793 }
George Liue99073f2022-12-09 11:06:16 +0800794 });
Ed Tanous002d39b2022-05-31 08:59:27 -0700795 });
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
George Liue99073f2022-12-09 11:06:16 +0800914 constexpr std::array<std::string_view, 1> interfaces = {
915 "xyz.openbmc_project.Software.Version"};
916 dbus::utility::getSubTree(
917 "/", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700918 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800919 swId](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 const dbus::utility::MapperGetSubTreeResponse& subtree) {
921 BMCWEB_LOG_DEBUG << "doGet callback...";
922 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700923 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700924 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700925 return;
926 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700927
Ed Tanous002d39b2022-05-31 08:59:27 -0700928 // Ensure we find our input swId, otherwise return an error
929 bool found = false;
930 for (const std::pair<std::string,
931 std::vector<std::pair<
932 std::string, std::vector<std::string>>>>&
933 obj : subtree)
934 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700935 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700936 {
937 continue;
938 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700939
Ed Tanous002d39b2022-05-31 08:59:27 -0700940 if (obj.second.empty())
941 {
942 continue;
943 }
944
945 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700946 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700947 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
948 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700949 }
950 if (!found)
951 {
952 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
953 messages::resourceMissingAtURI(
954 asyncResp->res, crow::utility::urlFromPieces(
955 "redfish", "v1", "UpdateService",
956 "FirmwareInventory", *swId));
957 return;
958 }
959 asyncResp->res.jsonValue["@odata.type"] =
960 "#SoftwareInventory.v1_1_0.SoftwareInventory";
961 asyncResp->res.jsonValue["Name"] = "Software Inventory";
962 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963
Ed Tanous002d39b2022-05-31 08:59:27 -0700964 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700965 sw_util::getSwUpdatableStatus(asyncResp, swId);
George Liue99073f2022-12-09 11:06:16 +0800966 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700967 });
968}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969
970} // namespace redfish