blob: d7dfbc4988982dbeaf62e75a9a63f23ee3c1142a [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
Ed Tanousd093c992023-01-19 19:01:49 -080028#include <boost/algorithm/string/case_conv.hpp>
George Liue99073f2022-12-09 11:06:16 +080029#include <boost/system/error_code.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070030#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080031#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020032#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033
George Liu2b731192023-01-11 16:27:13 +080034#include <array>
35#include <string_view>
36
Ed Tanous1abe55e2018-09-05 08:30:59 -070037namespace redfish
38{
Ed Tanous27826b52018-10-29 11:40:58 -070039
Andrew Geissler0e7de462019-03-04 19:11:54 -060040// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080041// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050042static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080043// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050044static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060045// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080046// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060047static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050048// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080049// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070050static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050051
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050053{
54 fwUpdateInProgress = false;
55 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070056 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050057}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070058inline static void activateImage(const std::string& objPath,
59 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050060{
61 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
62 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080063 [](const boost::system::error_code& errorCode) {
Ed Tanous002d39b2022-05-31 08:59:27 -070064 if (errorCode)
65 {
66 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
67 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
68 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050069 },
70 service, objPath, "org.freedesktop.DBus.Properties", "Set",
71 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080072 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080073 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050074}
Andrew Geissler0554c982019-04-23 14:40:12 -050075
76// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
77// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080078static void
79 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -050080 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050081{
Ed Tanousb9d36b42022-02-26 21:42:46 -080082 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050083
84 sdbusplus::message::object_path objPath;
85
86 m.read(objPath, interfacesProperties);
87
88 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Ed Tanouse3eb3d62022-12-21 11:56:07 -080089 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050090 {
91 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
92
93 if (interface.first == "xyz.openbmc_project.Software.Activation")
94 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050095 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +080096 constexpr std::array<std::string_view, 1> interfaces = {
97 "xyz.openbmc_project.Software.Activation"};
98 dbus::utility::getDbusObject(
99 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -0700100 [objPath, asyncResp, payload(std::move(payload))](
George Liu2b731192023-01-11 16:27:13 +0800101 const boost::system::error_code& errorCode,
Ed Tanousa3e65892021-09-16 14:13:20 -0700102 const std::vector<
103 std::pair<std::string, std::vector<std::string>>>&
104 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700105 if (errorCode)
106 {
107 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
108 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -0500109 if (asyncResp)
110 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 messages::internalError(asyncResp->res);
112 }
113 cleanUp();
114 return;
115 }
116 // Ensure we only got one service back
117 if (objInfo.size() != 1)
118 {
119 BMCWEB_LOG_ERROR << "Invalid Object Size "
120 << objInfo.size();
121 if (asyncResp)
122 {
123 messages::internalError(asyncResp->res);
124 }
125 cleanUp();
126 return;
127 }
128 // cancel timer only when
129 // xyz.openbmc_project.Software.Activation interface
130 // is added
131 fwAvailableTimer = nullptr;
132
133 activateImage(objPath.str, objInfo[0].first);
134 if (asyncResp)
135 {
136 std::shared_ptr<task::TaskData> task =
137 task::TaskData::createTask(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800138 [](const boost::system::error_code& ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500139 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700140 const std::shared_ptr<task::TaskData>&
141 taskData) {
142 if (ec)
143 {
144 return task::completed;
145 }
146
147 std::string iface;
148 dbus::utility::DBusPropertiesMap values;
149
150 std::string index = std::to_string(taskData->index);
151 msg.read(iface, values);
152
153 if (iface == "xyz.openbmc_project.Software.Activation")
154 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000155 const std::string* state = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700156 for (const auto& property : values)
157 {
158 if (property.first == "Activation")
159 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000160 state = std::get_if<std::string>(
161 &property.second);
162 if (state == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700163 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 taskData->messages.emplace_back(
165 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700166 return task::completed;
167 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 }
169 }
James Feist32898ce2020-03-10 16:16:52 -0700170
Ed Tanous002d39b2022-05-31 08:59:27 -0700171 if (state == nullptr)
172 {
173 return !task::completed;
174 }
James Feist32898ce2020-03-10 16:16:52 -0700175
Ed Tanous11ba3972022-07-11 09:50:41 -0700176 if (state->ends_with("Invalid") ||
177 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 {
179 taskData->state = "Exception";
180 taskData->status = "Warning";
181 taskData->messages.emplace_back(
182 messages::taskAborted(index));
183 return task::completed;
184 }
James Feiste5d50062020-05-11 17:29:00 -0700185
Ed Tanous11ba3972022-07-11 09:50:41 -0700186 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700187 {
188 taskData->state = "Stopping";
189 taskData->messages.emplace_back(
190 messages::taskPaused(index));
191
192 // its staged, set a long timer to
193 // allow them time to complete the
194 // update (probably cycle the
195 // system) if this expires then
196 // task will be cancelled
197 taskData->extendTimer(std::chrono::hours(5));
198 return !task::completed;
199 }
200
Ed Tanous11ba3972022-07-11 09:50:41 -0700201 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 {
203 taskData->messages.emplace_back(
204 messages::taskCompletedOK(index));
205 taskData->state = "Completed";
206 return task::completed;
207 }
208 }
209 else if (
210 iface ==
211 "xyz.openbmc_project.Software.ActivationProgress")
212 {
213
214 const uint8_t* progress = nullptr;
215 for (const auto& property : values)
216 {
217 if (property.first == "Progress")
218 {
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000219 progress =
220 std::get_if<uint8_t>(&property.second);
221 if (progress == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700222 {
James Feist32898ce2020-03-10 16:16:52 -0700223 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700224 messages::internalError());
225 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700226 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700227 }
228 }
James Feist32898ce2020-03-10 16:16:52 -0700229
Ed Tanous002d39b2022-05-31 08:59:27 -0700230 if (progress == nullptr)
231 {
232 return !task::completed;
233 }
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000234 taskData->percentComplete = *progress;
Ed Tanous002d39b2022-05-31 08:59:27 -0700235 taskData->messages.emplace_back(
Gayathri Leburu0fb5b502022-11-17 04:51:55 +0000236 messages::taskProgressChanged(index,
237 *progress));
James Feist32898ce2020-03-10 16:16:52 -0700238
Ed Tanous002d39b2022-05-31 08:59:27 -0700239 // if we're getting status updates it's
240 // still alive, update timer
241 taskData->extendTimer(std::chrono::minutes(5));
242 }
243
244 // as firmware update often results in a
245 // reboot, the task may never "complete"
246 // unless it is an error
247
248 return !task::completed;
249 },
250 "type='signal',interface='org.freedesktop.DBus.Properties',"
251 "member='PropertiesChanged',path='" +
252 objPath.str + "'");
253 task->startTimer(std::chrono::minutes(5));
254 task->populateResp(asyncResp->res);
255 task->payload.emplace(std::move(payload));
256 }
257 fwUpdateInProgress = false;
George Liu2b731192023-01-11 16:27:13 +0800258 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500259
260 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500261 }
262 }
263}
264
Andrew Geissler0554c982019-04-23 14:40:12 -0500265// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
266// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700267static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
269 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500270 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500271{
272 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800273 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500274 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500275 if (asyncResp)
276 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500277 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
278 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500279 return;
280 }
281
Andrew Geissler0554c982019-04-23 14:40:12 -0500282 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700283 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500284
Ed Tanous271584a2019-07-09 16:24:22 -0700285 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500286
287 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500288 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 cleanUp();
290 if (ec == boost::asio::error::operation_aborted)
291 {
292 // expected, we were canceled before the timer completed.
293 return;
294 }
295 BMCWEB_LOG_ERROR
296 << "Timed out waiting for firmware object being created";
297 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
298 if (ec)
299 {
300 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
301 return;
302 }
303 if (asyncResp)
304 {
305 redfish::messages::internalError(asyncResp->res);
306 }
307 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700308 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500309 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500310 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700311 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500312 };
313
314 fwUpdateInProgress = true;
315
Patrick Williams59d494e2022-07-22 19:26:55 -0500316 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500317 *crow::connections::systemBus,
318 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
319 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
320 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700321
Patrick Williams59d494e2022-07-22 19:26:55 -0500322 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700323 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800324 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
325 "member='InterfacesAdded',"
326 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500327 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
329 interfacesProperties;
330 sdbusplus::message::object_path objPath;
331 m.read(objPath, interfacesProperties);
332 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
333 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
334 interface : interfacesProperties)
335 {
336 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700337 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700338 for (const std::pair<std::string,
339 dbus::utility::DbusVariantType>& value :
340 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800341 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800343 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700344 continue;
345 }
346 const std::string* type =
347 std::get_if<std::string>(&value.second);
348 if (type == nullptr)
349 {
350 // if this was our message, timeout will cover it
351 return;
352 }
353 fwAvailableTimer = nullptr;
354 if (*type ==
355 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
356 {
357 redfish::messages::invalidUpload(asyncResp->res, url,
358 "Invalid archive");
359 }
360 else if (*type ==
361 "xyz.openbmc_project.Software.Image.Error."
362 "ManifestFileFailure")
363 {
364 redfish::messages::invalidUpload(asyncResp->res, url,
365 "Invalid manifest");
366 }
367 else if (
368 *type ==
369 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
370 {
371 redfish::messages::invalidUpload(
372 asyncResp->res, url, "Invalid image format");
373 }
374 else if (
375 *type ==
376 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
377 {
378 redfish::messages::invalidUpload(
379 asyncResp->res, url,
380 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600381
Ed Tanous002d39b2022-05-31 08:59:27 -0700382 redfish::messages::resourceAlreadyExists(
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800383 asyncResp->res, "UpdateService", "Version",
Ed Tanous002d39b2022-05-31 08:59:27 -0700384 "uploaded version");
385 }
386 else if (
387 *type ==
388 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
389 {
390 redfish::messages::resourceExhaustion(asyncResp->res,
391 url);
392 }
393 else
394 {
395 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800396 }
397 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600398 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 }
James Feist4cde5d92020-06-11 10:39:55 -0700400 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500401}
Jennifer Lee729dae72018-04-24 15:59:34 -0700402
Andrew Geissler0554c982019-04-23 14:40:12 -0500403/**
404 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
405 * SimpleUpdate action.
406 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700407inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500408{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700409 BMCWEB_ROUTE(
410 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700411 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 .methods(boost::beast::http::verb::post)(
413 [&app](const crow::Request& req,
414 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000415 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700416 {
417 return;
418 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700419
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 std::optional<std::string> transferProtocol;
421 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500422
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500424
Ed Tanous002d39b2022-05-31 08:59:27 -0700425 // User can pass in both TransferProtocol and ImageURI parameters or
426 // they can pass in just the ImageURI with the transfer protocol
427 // embedded within it.
428 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
429 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500430
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
432 transferProtocol, "ImageURI", imageURI))
433 {
434 BMCWEB_LOG_DEBUG
435 << "Missing TransferProtocol or ImageURI parameter";
436 return;
437 }
438 if (!transferProtocol)
439 {
440 // Must be option 2
441 // Verify ImageURI has transfer protocol in it
442 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500443 if ((separator == std::string::npos) ||
444 ((separator + 1) > imageURI.size()))
445 {
446 messages::actionParameterValueTypeError(
447 asyncResp->res, imageURI, "ImageURI",
448 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
450 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530451 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530452 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 transferProtocol = imageURI.substr(0, separator);
454 // Ensure protocol is upper case for a common comparison path
455 // below
456 boost::to_upper(*transferProtocol);
457 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
458 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530459
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 // Adjust imageURI to not have the protocol on it for parsing
461 // below
462 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
463 imageURI = imageURI.substr(separator + 3);
464 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
465 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530466
Ed Tanous002d39b2022-05-31 08:59:27 -0700467 // OpenBMC currently only supports TFTP
468 if (*transferProtocol != "TFTP")
469 {
470 messages::actionParameterNotSupported(asyncResp->res,
471 "TransferProtocol",
472 "UpdateService.SimpleUpdate");
473 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
474 << *transferProtocol;
475 return;
476 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700477
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 // Format should be <IP or Hostname>/<file> for imageURI
479 size_t separator = imageURI.find('/');
480 if ((separator == std::string::npos) ||
481 ((separator + 1) > imageURI.size()))
482 {
483 messages::actionParameterValueTypeError(
484 asyncResp->res, imageURI, "ImageURI",
485 "UpdateService.SimpleUpdate");
486 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
487 return;
488 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700489
Ed Tanous002d39b2022-05-31 08:59:27 -0700490 std::string tftpServer = imageURI.substr(0, separator);
491 std::string fwFile = imageURI.substr(separator + 1);
492 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700493
Ed Tanous002d39b2022-05-31 08:59:27 -0700494 // Setup callback for when new software detected
495 // Give TFTP 10 minutes to complete
496 monitorForSoftwareAvailable(
497 asyncResp, req,
498 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
499 600);
500
501 // TFTP can take up to 10 minutes depending on image size and
502 // connection speed. Return to caller as soon as the TFTP operation
503 // has been started. The callback above will ensure the activate
504 // is started once the download has completed
505 redfish::messages::success(asyncResp->res);
506
507 // Call TFTP service
508 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800509 [](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 if (ec)
511 {
512 // messages::internalError(asyncResp->res);
513 cleanUp();
514 BMCWEB_LOG_DEBUG << "error_code = " << ec;
515 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
516 }
517 else
518 {
519 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
520 }
521 },
522 "xyz.openbmc_project.Software.Download",
523 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
524 "DownloadViaTFTP", fwFile, tftpServer);
525
526 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700527 });
528}
529
Ed Tanousc2051d12022-05-11 12:21:55 -0700530inline void
531 handleUpdateServicePost(App& app, const crow::Request& req,
532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
533{
Carson Labrado3ba00072022-06-06 19:40:56 +0000534 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700535 {
536 return;
537 }
538 BMCWEB_LOG_DEBUG << "doPost...";
539
540 // Setup callback for when new software detected
541 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
542
543 std::string filepath(
544 "/tmp/images/" +
545 boost::uuids::to_string(boost::uuids::random_generator()()));
546 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
547 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
548 std::ofstream::trunc);
549 out << req.body;
550 out.close();
551 BMCWEB_LOG_DEBUG << "file upload complete!!";
552}
553
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700554inline void requestRoutesUpdateService(App& app)
555{
556 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700557 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700558 .methods(boost::beast::http::verb::get)(
559 [&app](const crow::Request& req,
560 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000561 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700562 {
563 return;
564 }
565 asyncResp->res.jsonValue["@odata.type"] =
566 "#UpdateService.v1_5_0.UpdateService";
567 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
568 asyncResp->res.jsonValue["Id"] = "UpdateService";
569 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
570 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700571
Ed Tanous32ca38a2022-05-11 12:36:59 -0700572#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700573 // See note about later on in this file about why this is neccesary
574 // This is "Wrong" per the standard, but is done temporarily to
575 // avoid noise in failing tests as people transition to having this
576 // option disabled
577 asyncResp->res.addHeader(boost::beast::http::field::allow,
578 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700579#endif
580
Ed Tanous002d39b2022-05-31 08:59:27 -0700581 asyncResp->res.jsonValue["HttpPushUri"] =
582 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700583
Ed Tanous002d39b2022-05-31 08:59:27 -0700584 // UpdateService cannot be disabled
585 asyncResp->res.jsonValue["ServiceEnabled"] = true;
586 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
587 "/redfish/v1/UpdateService/FirmwareInventory";
588 // Get the MaxImageSizeBytes
589 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
590 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530591
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700592#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700593 // Update Actions object.
594 nlohmann::json& updateSvcSimpleUpdate =
595 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
596 updateSvcSimpleUpdate["target"] =
597 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
598 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
599 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700600#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700601 // Get the current ApplyTime value
602 sdbusplus::asio::getProperty<std::string>(
603 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
604 "/xyz/openbmc_project/software/apply_time",
605 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800606 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700607 const std::string& applyTime) {
608 if (ec)
609 {
610 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
611 messages::internalError(asyncResp->res);
612 return;
613 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530614
Ed Tanous002d39b2022-05-31 08:59:27 -0700615 // Store the ApplyTime Value
616 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
617 "RequestedApplyTimes.Immediate")
618 {
619 asyncResp->res.jsonValue["HttpPushUriOptions"]
620 ["HttpPushUriApplyTime"]["ApplyTime"] =
621 "Immediate";
622 }
623 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
624 "RequestedApplyTimes.OnReset")
625 {
626 asyncResp->res.jsonValue["HttpPushUriOptions"]
627 ["HttpPushUriApplyTime"]["ApplyTime"] =
628 "OnReset";
629 }
630 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700631 });
632 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700633 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700634 .methods(boost::beast::http::verb::patch)(
635 [&app](const crow::Request& req,
636 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000637 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700638 {
639 return;
640 }
641 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530642
Ed Tanous002d39b2022-05-31 08:59:27 -0700643 std::optional<nlohmann::json> pushUriOptions;
644 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
645 pushUriOptions))
646 {
647 return;
648 }
649
650 if (pushUriOptions)
651 {
652 std::optional<nlohmann::json> pushUriApplyTime;
653 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
654 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800655 {
656 return;
657 }
658
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800660 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700661 std::optional<std::string> applyTime;
662 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
663 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700665 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700667
Ed Tanous002d39b2022-05-31 08:59:27 -0700668 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700670 std::string applyTimeNewVal;
671 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700672 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700673 applyTimeNewVal =
674 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
675 }
676 else if (applyTime == "OnReset")
677 {
678 applyTimeNewVal =
679 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
680 }
681 else
682 {
683 BMCWEB_LOG_INFO
684 << "ApplyTime value is not in the list of acceptable values";
685 messages::propertyValueNotInList(
686 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700687 return;
688 }
689
Ed Tanous002d39b2022-05-31 08:59:27 -0700690 // Set the requested image apply time value
691 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800692 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700693 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700694 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700695 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
696 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700697 return;
698 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 messages::success(asyncResp->res);
700 },
701 "xyz.openbmc_project.Settings",
702 "/xyz/openbmc_project/software/apply_time",
703 "org.freedesktop.DBus.Properties", "Set",
704 "xyz.openbmc_project.Software.ApplyTime",
705 "RequestedApplyTime",
706 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700707 }
George Liu0fda0f12021-11-16 10:06:17 +0800708 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700709 }
George Liu0fda0f12021-11-16 10:06:17 +0800710 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700711
Ed Tanous4dc23f32022-05-11 11:32:19 -0700712// The "old" behavior of the update service URI causes redfish-service validator
713// failures when the Allow header is supported, given that in the spec,
714// UpdateService does not allow POST. in openbmc, we unfortunately reused that
715// resource as our HttpPushUri as well. A number of services, including the
716// openbmc tests, and documentation have hardcoded that erroneous API, instead
717// of relying on HttpPushUri as the spec requires. This option will exist
718// temporarily to allow the old behavior until Q4 2022, at which time it will be
719// removed.
720#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700721 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700722 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700723 .methods(boost::beast::http::verb::post)(
724 [&app](const crow::Request& req,
725 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
726 asyncResp->res.addHeader(
727 boost::beast::http::field::warning,
728 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
729 "the value contained within HttpPushUri.\"");
730 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700731 });
732#endif
733 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
734 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700735 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700736 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700737}
738
739inline void requestRoutesSoftwareInventoryCollection(App& app)
740{
741 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700742 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700743 .methods(boost::beast::http::verb::get)(
744 [&app](const crow::Request& req,
745 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000746 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700747 {
748 return;
749 }
750 asyncResp->res.jsonValue["@odata.type"] =
751 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
752 asyncResp->res.jsonValue["@odata.id"] =
753 "/redfish/v1/UpdateService/FirmwareInventory";
754 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
755
George Liue99073f2022-12-09 11:06:16 +0800756 // Note that only firmware levels associated with a device
757 // are stored under /xyz/openbmc_project/software therefore
758 // to ensure only real FirmwareInventory items are returned,
759 // this full object path must be used here as input to
760 // mapper
761 constexpr std::array<std::string_view, 1> interfaces = {
762 "xyz.openbmc_project.Software.Version"};
763 dbus::utility::getSubTree(
764 "/xyz/openbmc_project/software", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700765 [asyncResp](
George Liue99073f2022-12-09 11:06:16 +0800766 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700767 const dbus::utility::MapperGetSubTreeResponse& subtree) {
768 if (ec)
769 {
770 messages::internalError(asyncResp->res);
771 return;
772 }
773 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
774 asyncResp->res.jsonValue["Members@odata.count"] = 0;
775
776 for (const auto& obj : subtree)
777 {
778 sdbusplus::message::object_path path(obj.first);
779 std::string swId = path.filename();
780 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700781 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700782 messages::internalError(asyncResp->res);
783 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700784 return;
785 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700786
Ed Tanous002d39b2022-05-31 08:59:27 -0700787 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
788 nlohmann::json::object_t member;
Willy Tueddfc432022-09-26 16:46:38 +0000789 member["@odata.id"] = crow::utility::urlFromPieces(
790 "redfish", "v1", "UpdateService", "FirmwareInventory",
791 swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700792 members.push_back(std::move(member));
793 asyncResp->res.jsonValue["Members@odata.count"] =
794 members.size();
795 }
George Liue99073f2022-12-09 11:06:16 +0800796 });
Ed Tanous002d39b2022-05-31 08:59:27 -0700797 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700798}
799/* Fill related item links (i.e. bmc, bios) in for inventory */
800inline static void
801 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
802 const std::string& purpose)
803{
Willy Tueee00132022-06-14 14:53:17 -0700804 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700805 {
806 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700807 nlohmann::json::object_t item;
808 item["@odata.id"] = "/redfish/v1/Managers/bmc";
809 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700810 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
811 }
Willy Tueee00132022-06-14 14:53:17 -0700812 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700813 {
814 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700815 nlohmann::json::object_t item;
816 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
817 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800818 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700819 }
820 else
821 {
822 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
823 }
824}
825
Willy Tuaf246602022-06-14 15:51:53 -0700826inline void
827 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
828 const std::string& service, const std::string& path,
829 const std::string& swId)
830{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200831 sdbusplus::asio::getAllProperties(
832 *crow::connections::systemBus, service, path,
833 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -0700834 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800835 swId](const boost::system::error_code& errorCode,
Willy Tuaf246602022-06-14 15:51:53 -0700836 const dbus::utility::DBusPropertiesMap& propertiesList) {
837 if (errorCode)
838 {
839 messages::internalError(asyncResp->res);
840 return;
841 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200842
Willy Tuaf246602022-06-14 15:51:53 -0700843 const std::string* swInvPurpose = nullptr;
844 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200845
846 const bool success = sdbusplus::unpackPropertiesNoThrow(
847 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
848 swInvPurpose, "Version", version);
849
850 if (!success)
Willy Tuaf246602022-06-14 15:51:53 -0700851 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200852 messages::internalError(asyncResp->res);
853 return;
Willy Tuaf246602022-06-14 15:51:53 -0700854 }
855
856 if (swInvPurpose == nullptr)
857 {
858 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
859 messages::internalError(asyncResp->res);
860 return;
861 }
862
863 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
864
865 if (version == nullptr)
866 {
867 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
868
869 messages::internalError(asyncResp->res);
870
871 return;
872 }
873 asyncResp->res.jsonValue["Version"] = *version;
874 asyncResp->res.jsonValue["Id"] = swId;
875
876 // swInvPurpose is of format:
877 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
878 // Translate this to "ABC image"
879 size_t endDesc = swInvPurpose->rfind('.');
880 if (endDesc == std::string::npos)
881 {
882 messages::internalError(asyncResp->res);
883 return;
884 }
885 endDesc++;
886 if (endDesc >= swInvPurpose->size())
887 {
888 messages::internalError(asyncResp->res);
889 return;
890 }
891
892 std::string formatDesc = swInvPurpose->substr(endDesc);
893 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
894 getRelatedItems(asyncResp, *swInvPurpose);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200895 });
Willy Tuaf246602022-06-14 15:51:53 -0700896}
897
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700898inline void requestRoutesSoftwareInventory(App& app)
899{
900 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700901 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700902 .methods(boost::beast::http::verb::get)(
903 [&app](const crow::Request& req,
904 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
905 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000906 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700907 {
908 return;
909 }
910 std::shared_ptr<std::string> swId =
911 std::make_shared<std::string>(param);
912
Willy Tueddfc432022-09-26 16:46:38 +0000913 asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
914 "redfish", "v1", "UpdateService", "FirmwareInventory", *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700915
George Liue99073f2022-12-09 11:06:16 +0800916 constexpr std::array<std::string_view, 1> interfaces = {
917 "xyz.openbmc_project.Software.Version"};
918 dbus::utility::getSubTree(
919 "/", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800921 swId](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700922 const dbus::utility::MapperGetSubTreeResponse& subtree) {
923 BMCWEB_LOG_DEBUG << "doGet callback...";
924 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700925 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700926 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700927 return;
928 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700929
Ed Tanous002d39b2022-05-31 08:59:27 -0700930 // Ensure we find our input swId, otherwise return an error
931 bool found = false;
932 for (const std::pair<std::string,
933 std::vector<std::pair<
934 std::string, std::vector<std::string>>>>&
935 obj : subtree)
936 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700937 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700938 {
939 continue;
940 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700941
Ed Tanous002d39b2022-05-31 08:59:27 -0700942 if (obj.second.empty())
943 {
944 continue;
945 }
946
947 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700948 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700949 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
950 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700951 }
952 if (!found)
953 {
954 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
955 messages::resourceMissingAtURI(
956 asyncResp->res, crow::utility::urlFromPieces(
957 "redfish", "v1", "UpdateService",
958 "FirmwareInventory", *swId));
959 return;
960 }
961 asyncResp->res.jsonValue["@odata.type"] =
962 "#SoftwareInventory.v1_1_0.SoftwareInventory";
963 asyncResp->res.jsonValue["Name"] = "Software Inventory";
964 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965
Ed Tanous002d39b2022-05-31 08:59:27 -0700966 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700967 sw_util::getSwUpdatableStatus(asyncResp, swId);
George Liue99073f2022-12-09 11:06:16 +0800968 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700969 });
970}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971
972} // namespace redfish