blob: c8b13816ed25ce44e5f4f736fb5506aabd0736c7 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070020#include <app.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080021#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070022#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070023#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070024#include <sdbusplus/asio/property.hpp>
Andrew Geissler87d84722019-02-28 14:28:39 -060025#include <utils/fw_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Ed Tanous27826b52018-10-29 11:40:58 -070029
Andrew Geissler0e7de462019-03-04 19:11:54 -060030// Match signals added on software path
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070031static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
James Feist4cde5d92020-06-11 10:39:55 -070032static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060033// Only allow one update at a time
34static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050035// Timer for software available
Ed Tanous271584a2019-07-09 16:24:22 -070036static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050037
John Edward Broadbent7e860f12021-04-08 15:57:16 -070038inline static void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -050039{
40 fwUpdateInProgress = false;
41 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070042 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050043}
John Edward Broadbent7e860f12021-04-08 15:57:16 -070044inline static void activateImage(const std::string& objPath,
45 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050046{
47 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
48 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000049 [](const boost::system::error_code errorCode) {
50 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050051 {
Ed Tanous81ce6092020-12-17 16:54:55 +000052 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
53 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler86adcd62019-04-18 10:58:05 -050054 }
55 },
56 service, objPath, "org.freedesktop.DBus.Properties", "Set",
57 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
Ed Tanous168e20c2021-12-13 14:39:53 -080058 dbus::utility::DbusVariantType(
George Liu0fda0f12021-11-16 10:06:17 +080059 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"));
Andrew Geissler86adcd62019-04-18 10:58:05 -050060}
Andrew Geissler0554c982019-04-23 14:40:12 -050061
62// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
63// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080064static void
65 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
66 sdbusplus::message::message& m,
Ed Tanousa3e65892021-09-16 14:13:20 -070067 task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050068{
Ed Tanousb9d36b42022-02-26 21:42:46 -080069 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050070
71 sdbusplus::message::object_path objPath;
72
73 m.read(objPath, interfacesProperties);
74
75 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050076 for (auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050077 {
78 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
79
80 if (interface.first == "xyz.openbmc_project.Software.Activation")
81 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050082 // Retrieve service and activate
83 crow::connections::systemBus->async_method_call(
Ed Tanousa3e65892021-09-16 14:13:20 -070084 [objPath, asyncResp, payload(std::move(payload))](
85 const boost::system::error_code errorCode,
86 const std::vector<
87 std::pair<std::string, std::vector<std::string>>>&
88 objInfo) mutable {
Ed Tanous81ce6092020-12-17 16:54:55 +000089 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050090 {
Ed Tanous81ce6092020-12-17 16:54:55 +000091 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
Andrew Geissler86adcd62019-04-18 10:58:05 -050092 BMCWEB_LOG_DEBUG << "error msg = "
Ed Tanous81ce6092020-12-17 16:54:55 +000093 << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050094 if (asyncResp)
95 {
96 messages::internalError(asyncResp->res);
97 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050098 cleanUp();
99 return;
100 }
101 // Ensure we only got one service back
102 if (objInfo.size() != 1)
103 {
104 BMCWEB_LOG_ERROR << "Invalid Object Size "
105 << objInfo.size();
Andrew Geissler0554c982019-04-23 14:40:12 -0500106 if (asyncResp)
107 {
108 messages::internalError(asyncResp->res);
109 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500110 cleanUp();
111 return;
112 }
113 // cancel timer only when
114 // xyz.openbmc_project.Software.Activation interface
115 // is added
116 fwAvailableTimer = nullptr;
117
118 activateImage(objPath.str, objInfo[0].first);
Andrew Geissler0554c982019-04-23 14:40:12 -0500119 if (asyncResp)
120 {
James Feist32898ce2020-03-10 16:16:52 -0700121 std::shared_ptr<task::TaskData> task =
122 task::TaskData::createTask(
123 [](boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500124 sdbusplus::message::message& msg,
125 const std::shared_ptr<task::TaskData>&
126 taskData) {
James Feist32898ce2020-03-10 16:16:52 -0700127 if (ec)
128 {
129 return task::completed;
130 }
131
132 std::string iface;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800133 dbus::utility::DBusPropertiesMap values;
James Feist32898ce2020-03-10 16:16:52 -0700134
James Feiste5d50062020-05-11 17:29:00 -0700135 std::string index =
136 std::to_string(taskData->index);
James Feistfd9ab9e2020-05-19 13:48:07 -0700137 msg.read(iface, values);
James Feiste5d50062020-05-11 17:29:00 -0700138
George Liu0fda0f12021-11-16 10:06:17 +0800139 if (iface ==
140 "xyz.openbmc_project.Software.Activation")
James Feist32898ce2020-03-10 16:16:52 -0700141 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800142 std::string* state = nullptr;
143 for (const auto& property : values)
James Feistfd9ab9e2020-05-19 13:48:07 -0700144 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800145 if (property.first == "Activation")
146 {
147 const std::string* state =
148 std::get_if<std::string>(
149 &property.second);
150 if (state == nullptr)
151 {
152 taskData->messages
153 .emplace_back(
154 messages::
155 internalError());
156 return task::completed;
157 }
158 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700159 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700160
161 if (state == nullptr)
162 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800163 return !task::completed;
James Feistfd9ab9e2020-05-19 13:48:07 -0700164 }
165
166 if (boost::ends_with(*state,
167 "Invalid") ||
168 boost::ends_with(*state, "Failed"))
169 {
170 taskData->state = "Exception";
171 taskData->status = "Warning";
172 taskData->messages.emplace_back(
173 messages::taskAborted(index));
174 return task::completed;
175 }
176
177 if (boost::ends_with(*state, "Staged"))
178 {
179 taskData->state = "Stopping";
180 taskData->messages.emplace_back(
181 messages::taskPaused(index));
182
183 // its staged, set a long timer to
184 // allow them time to complete the
185 // update (probably cycle the
186 // system) if this expires then
187 // task will be cancelled
188 taskData->extendTimer(
189 std::chrono::hours(5));
190 return !task::completed;
191 }
192
193 if (boost::ends_with(*state, "Active"))
194 {
195 taskData->messages.emplace_back(
196 messages::taskCompletedOK(
197 index));
198 taskData->state = "Completed";
199 return task::completed;
200 }
James Feist32898ce2020-03-10 16:16:52 -0700201 }
George Liu0fda0f12021-11-16 10:06:17 +0800202 else if (
203 iface ==
204 "xyz.openbmc_project.Software.ActivationProgress")
James Feist32898ce2020-03-10 16:16:52 -0700205 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800206
207 const uint8_t* progress = nullptr;
208 for (const auto& property : values)
James Feistfd9ab9e2020-05-19 13:48:07 -0700209 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800210 if (property.first == "Progress")
211 {
212 const std::string* progress =
213 std::get_if<std::string>(
214 &property.second);
215 if (progress == nullptr)
216 {
217 taskData->messages
218 .emplace_back(
219 messages::
220 internalError());
221 return task::completed;
222 }
223 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700224 }
James Feist32898ce2020-03-10 16:16:52 -0700225
James Feistfd9ab9e2020-05-19 13:48:07 -0700226 if (progress == nullptr)
227 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800228 return !task::completed;
James Feistfd9ab9e2020-05-19 13:48:07 -0700229 }
George Liu6868ff52021-01-02 11:37:41 +0800230 taskData->percentComplete =
231 static_cast<int>(*progress);
James Feist32898ce2020-03-10 16:16:52 -0700232 taskData->messages.emplace_back(
James Feistfd9ab9e2020-05-19 13:48:07 -0700233 messages::taskProgressChanged(
234 index, static_cast<size_t>(
235 *progress)));
236
237 // if we're getting status updates it's
238 // still alive, update timer
239 taskData->extendTimer(
240 std::chrono::minutes(5));
James Feist32898ce2020-03-10 16:16:52 -0700241 }
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 },
George Liu0fda0f12021-11-16 10:06:17 +0800249 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feistfd9ab9e2020-05-19 13:48:07 -0700250 "member='PropertiesChanged',path='" +
James Feist32898ce2020-03-10 16:16:52 -0700251 objPath.str + "'");
252 task->startTimer(std::chrono::minutes(5));
253 task->populateResp(asyncResp->res);
Ed Tanousa3e65892021-09-16 14:13:20 -0700254 task->payload.emplace(std::move(payload));
Andrew Geissler0554c982019-04-23 14:40:12 -0500255 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500256 fwUpdateInProgress = false;
257 },
258 "xyz.openbmc_project.ObjectMapper",
259 "/xyz/openbmc_project/object_mapper",
260 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500262 "xyz.openbmc_project.Software.Activation"});
263 }
264 }
265}
266
Andrew Geissler0554c982019-04-23 14:40:12 -0500267// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
268// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700269static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
271 const crow::Request& req, const std::string& url,
272 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500273{
274 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800275 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500277 if (asyncResp)
278 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500279 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
280 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500281 return;
282 }
283
Andrew Geissler0554c982019-04-23 14:40:12 -0500284 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700285 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500286
Ed Tanous271584a2019-07-09 16:24:22 -0700287 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500288
289 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500290 [asyncResp](const boost::system::error_code& ec) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500291 cleanUp();
292 if (ec == boost::asio::error::operation_aborted)
293 {
294 // expected, we were canceled before the timer completed.
295 return;
296 }
297 BMCWEB_LOG_ERROR
298 << "Timed out waiting for firmware object being created";
299 BMCWEB_LOG_ERROR
300 << "FW image may has already been uploaded to server";
301 if (ec)
302 {
303 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
304 return;
305 }
Andrew Geissler0554c982019-04-23 14:40:12 -0500306 if (asyncResp)
307 {
308 redfish::messages::internalError(asyncResp->res);
309 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500310 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700311 task::Payload payload(req);
312 auto callback = [asyncResp,
313 payload](sdbusplus::message::message& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500314 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700315 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500316 };
317
318 fwUpdateInProgress = true;
319
320 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
321 *crow::connections::systemBus,
322 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
323 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
324 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700325
326 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
327 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800328 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
329 "member='InterfacesAdded',"
330 "path='/xyz/openbmc_project/logging'",
James Feist4cde5d92020-06-11 10:39:55 -0700331 [asyncResp, url](sdbusplus::message::message& m) {
Brian Mae1cc4822021-12-01 17:05:54 +0800332 std::vector<
333 std::pair<std::string, dbus::utility::DBusPropertiesMap>>
334 interfacesProperties;
335 sdbusplus::message::object_path objPath;
336 m.read(objPath, interfacesProperties);
337 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
338 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
339 interface : interfacesProperties)
James Feist4cde5d92020-06-11 10:39:55 -0700340 {
Brian Mae1cc4822021-12-01 17:05:54 +0800341 if (interface.first == "xyz.openbmc_project.Logging.Entry")
342 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800343 for (const std::pair<std::string,
344 dbus::utility::DbusVariantType>&
345 value : interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800346 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800347 if (value.first != "Message")
348 {
349 continue;
350 }
351 const std::string* type =
352 std::get_if<std::string>(&value.second);
353 if (type == nullptr)
354 {
355 // if this was our message, timeout will cover it
356 return;
357 }
358 fwAvailableTimer = nullptr;
359 if (*type ==
360 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
361 {
362 redfish::messages::invalidUpload(
363 asyncResp->res, url, "Invalid archive");
364 }
365 else if (*type ==
366 "xyz.openbmc_project.Software.Image.Error."
367 "ManifestFileFailure")
368 {
369 redfish::messages::invalidUpload(
370 asyncResp->res, url, "Invalid manifest");
371 }
372 else if (
373 *type ==
374 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
375 {
376 redfish::messages::invalidUpload(
377 asyncResp->res, url, "Invalid image format");
378 }
379 else if (
380 *type ==
381 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
382 {
383 redfish::messages::invalidUpload(
384 asyncResp->res, url,
385 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600386
Ed Tanous711ac7a2021-12-20 09:34:41 -0800387 redfish::messages::resourceAlreadyExists(
388 asyncResp->res,
389 "UpdateService.v1_5_0.UpdateService", "Version",
390 "uploaded version");
391 }
392 else if (
393 *type ==
394 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
395 {
396 redfish::messages::resourceExhaustion(
397 asyncResp->res, url);
398 }
399 else
400 {
401 redfish::messages::internalError(asyncResp->res);
402 }
Brian Mae1cc4822021-12-01 17:05:54 +0800403 }
404 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600405 }
James Feist4cde5d92020-06-11 10:39:55 -0700406 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500407}
Jennifer Lee729dae72018-04-24 15:59:34 -0700408
Andrew Geissler0554c982019-04-23 14:40:12 -0500409/**
410 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
411 * SimpleUpdate action.
412 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700413inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500414{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700415 BMCWEB_ROUTE(
416 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700417 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700418 .methods(
419 boost::beast::http::verb::
Ed Tanous45ca1b82022-03-25 13:07:27 -0700420 post)([&app](
421 const crow::Request& req,
422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
423 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
424 {
425 return;
426 }
427
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700428 std::optional<std::string> transferProtocol;
429 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500430
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700431 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500432
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700433 // User can pass in both TransferProtocol and ImageURI parameters or
434 // they can pass in just the ImageURI with the transfer protocol
435 // embedded within it.
436 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
437 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500438
Willy Tu15ed6782021-12-14 11:03:16 -0800439 if (!json_util::readJsonAction(req, asyncResp->res,
440 "TransferProtocol", transferProtocol,
441 "ImageURI", imageURI))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700442 {
443 BMCWEB_LOG_DEBUG
444 << "Missing TransferProtocol or ImageURI parameter";
445 return;
446 }
447 if (!transferProtocol)
448 {
449 // Must be option 2
450 // Verify ImageURI has transfer protocol in it
451 size_t separator = imageURI.find(':');
452 if ((separator == std::string::npos) ||
453 ((separator + 1) > imageURI.size()))
454 {
455 messages::actionParameterValueTypeError(
456 asyncResp->res, imageURI, "ImageURI",
457 "UpdateService.SimpleUpdate");
458 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
459 << imageURI;
460 return;
461 }
462 transferProtocol = imageURI.substr(0, separator);
463 // Ensure protocol is upper case for a common comparison path
464 // below
465 boost::to_upper(*transferProtocol);
466 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
467 << *transferProtocol;
Andrew Geissler0554c982019-04-23 14:40:12 -0500468
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700469 // Adjust imageURI to not have the protocol on it for parsing
470 // below
471 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
472 imageURI = imageURI.substr(separator + 3);
473 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
474 }
475
476 // OpenBMC currently only supports TFTP
477 if (*transferProtocol != "TFTP")
478 {
479 messages::actionParameterNotSupported(
480 asyncResp->res, "TransferProtocol",
481 "UpdateService.SimpleUpdate");
482 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
483 << *transferProtocol;
484 return;
485 }
486
487 // Format should be <IP or Hostname>/<file> for imageURI
488 size_t separator = imageURI.find('/');
Andrew Geissler0554c982019-04-23 14:40:12 -0500489 if ((separator == std::string::npos) ||
490 ((separator + 1) > imageURI.size()))
491 {
492 messages::actionParameterValueTypeError(
493 asyncResp->res, imageURI, "ImageURI",
494 "UpdateService.SimpleUpdate");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700495 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530496 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530497 }
498
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700499 std::string tftpServer = imageURI.substr(0, separator);
500 std::string fwFile = imageURI.substr(separator + 1);
501 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530502
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700503 // Setup callback for when new software detected
504 // Give TFTP 10 minutes to complete
505 monitorForSoftwareAvailable(
506 asyncResp, req,
507 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
508 600);
509
510 // TFTP can take up to 10 minutes depending on image size and
511 // connection speed. Return to caller as soon as the TFTP operation
512 // has been started. The callback above will ensure the activate
513 // is started once the download has completed
514 redfish::messages::success(asyncResp->res);
515
516 // Call TFTP service
517 crow::connections::systemBus->async_method_call(
518 [](const boost::system::error_code ec) {
519 if (ec)
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530520 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700521 // messages::internalError(asyncResp->res);
522 cleanUp();
523 BMCWEB_LOG_DEBUG << "error_code = " << ec;
524 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530525 }
526 else
527 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700528 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
529 }
530 },
531 "xyz.openbmc_project.Software.Download",
532 "/xyz/openbmc_project/software",
533 "xyz.openbmc_project.Common.TFTP", "DownloadViaTFTP", fwFile,
534 tftpServer);
535
536 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
537 });
538}
539
Ed Tanousc2051d12022-05-11 12:21:55 -0700540inline void
541 handleUpdateServicePost(App& app, const crow::Request& req,
542 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
543{
544 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
545 {
546 return;
547 }
548 BMCWEB_LOG_DEBUG << "doPost...";
549
550 // Setup callback for when new software detected
551 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
552
553 std::string filepath(
554 "/tmp/images/" +
555 boost::uuids::to_string(boost::uuids::random_generator()()));
556 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
557 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
558 std::ofstream::trunc);
559 out << req.body;
560 out.close();
561 BMCWEB_LOG_DEBUG << "file upload complete!!";
562}
563
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700564inline void requestRoutesUpdateService(App& app)
565{
566 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700567 .privileges(redfish::privileges::getUpdateService)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700568 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
569 const std::shared_ptr<
570 bmcweb::AsyncResp>&
571 asyncResp) {
572 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
573 {
574 return;
575 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700576 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan0588a3b2021-06-10 18:20:36 +0800577 "#UpdateService.v1_5_0.UpdateService";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700578 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
579 asyncResp->res.jsonValue["Id"] = "UpdateService";
580 asyncResp->res.jsonValue["Description"] =
581 "Service for Software Update";
582 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700583
Ed Tanous32ca38a2022-05-11 12:36:59 -0700584#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
585 // See note about later on in this file about why this is neccesary
586 // This is "Wrong" per the standard, but is done temporarily to
587 // avoid noise in failing tests as people transition to having this
588 // option disabled
589 asyncResp->res.addHeader(boost::beast::http::field::allow,
590 "GET, PATCH, HEAD");
591#endif
592
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700593 asyncResp->res.jsonValue["HttpPushUri"] =
Ed Tanous4dc23f32022-05-11 11:32:19 -0700594 "/redfish/v1/UpdateService/update";
595
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700596 // UpdateService cannot be disabled
597 asyncResp->res.jsonValue["ServiceEnabled"] = true;
Ed Tanous14766872022-03-15 10:44:42 -0700598 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
599 "/redfish/v1/UpdateService/FirmwareInventory";
Tejas Patild61e5192021-06-04 15:49:35 +0530600 // Get the MaxImageSizeBytes
601 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
602 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
603
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700604#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
605 // Update Actions object.
606 nlohmann::json& updateSvcSimpleUpdate =
607 asyncResp->res
608 .jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
609 updateSvcSimpleUpdate["target"] =
610 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
611 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
612 {"TFTP"};
613#endif
614 // Get the current ApplyTime value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700615 sdbusplus::asio::getProperty<std::string>(
616 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
617 "/xyz/openbmc_project/software/apply_time",
618 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700619 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700620 const std::string& applyTime) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 if (ec)
622 {
623 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
624 messages::internalError(asyncResp->res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530625 return;
626 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530627
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700628 // Store the ApplyTime Value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700629 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
630 "RequestedApplyTimes.Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700631 {
632 asyncResp->res
633 .jsonValue["HttpPushUriOptions"]
634 ["HttpPushUriApplyTime"]["ApplyTime"] =
635 "Immediate";
636 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700637 else if (applyTime ==
638 "xyz.openbmc_project.Software.ApplyTime."
639 "RequestedApplyTimes.OnReset")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700640 {
641 asyncResp->res
642 .jsonValue["HttpPushUriOptions"]
643 ["HttpPushUriApplyTime"]["ApplyTime"] =
644 "OnReset";
645 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700646 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700647 });
648 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700649 .privileges(redfish::privileges::patchUpdateService)
George Liu0fda0f12021-11-16 10:06:17 +0800650 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700651 boost::beast::http::verb::patch)([&app](const crow::Request& req,
652 const std::shared_ptr<
653 bmcweb::AsyncResp>&
654 asyncResp) {
655 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
656 {
657 return;
658 }
George Liu0fda0f12021-11-16 10:06:17 +0800659 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530660
George Liu0fda0f12021-11-16 10:06:17 +0800661 std::optional<nlohmann::json> pushUriOptions;
Willy Tu15ed6782021-12-14 11:03:16 -0800662 if (!json_util::readJsonPatch(req, asyncResp->res,
663 "HttpPushUriOptions", pushUriOptions))
George Liu0fda0f12021-11-16 10:06:17 +0800664 {
665 return;
666 }
667
668 if (pushUriOptions)
669 {
670 std::optional<nlohmann::json> pushUriApplyTime;
671 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
672 "HttpPushUriApplyTime",
673 pushUriApplyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700675 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700677
George Liu0fda0f12021-11-16 10:06:17 +0800678 if (pushUriApplyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 {
George Liu0fda0f12021-11-16 10:06:17 +0800680 std::optional<std::string> applyTime;
681 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
682 "ApplyTime", applyTime))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700683 {
684 return;
685 }
686
George Liu0fda0f12021-11-16 10:06:17 +0800687 if (applyTime)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700688 {
George Liu0fda0f12021-11-16 10:06:17 +0800689 std::string applyTimeNewVal;
690 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700691 {
George Liu0fda0f12021-11-16 10:06:17 +0800692 applyTimeNewVal =
693 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
694 }
695 else if (applyTime == "OnReset")
696 {
697 applyTimeNewVal =
698 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
699 }
700 else
701 {
702 BMCWEB_LOG_INFO
703 << "ApplyTime value is not in the list of acceptable values";
704 messages::propertyValueNotInList(
705 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700706 return;
707 }
708
George Liu0fda0f12021-11-16 10:06:17 +0800709 // Set the requested image apply time value
710 crow::connections::systemBus->async_method_call(
711 [asyncResp](const boost::system::error_code ec) {
712 if (ec)
713 {
714 BMCWEB_LOG_ERROR
715 << "D-Bus responses error: " << ec;
716 messages::internalError(asyncResp->res);
717 return;
718 }
719 messages::success(asyncResp->res);
720 },
721 "xyz.openbmc_project.Settings",
722 "/xyz/openbmc_project/software/apply_time",
723 "org.freedesktop.DBus.Properties", "Set",
724 "xyz.openbmc_project.Software.ApplyTime",
725 "RequestedApplyTime",
Ed Tanous168e20c2021-12-13 14:39:53 -0800726 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700727 }
728 }
George Liu0fda0f12021-11-16 10:06:17 +0800729 }
730 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700731
Ed Tanous4dc23f32022-05-11 11:32:19 -0700732// The "old" behavior of the update service URI causes redfish-service validator
733// failures when the Allow header is supported, given that in the spec,
734// UpdateService does not allow POST. in openbmc, we unfortunately reused that
735// resource as our HttpPushUri as well. A number of services, including the
736// openbmc tests, and documentation have hardcoded that erroneous API, instead
737// of relying on HttpPushUri as the spec requires. This option will exist
738// temporarily to allow the old behavior until Q4 2022, at which time it will be
739// removed.
740#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700741 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700742 .privileges(redfish::privileges::postUpdateService)
Ed Tanous4dc23f32022-05-11 11:32:19 -0700743 .methods(
744 boost::beast::http::verb::
745 post)([&app](
746 const crow::Request& req,
747 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
748 asyncResp->res.addHeader(
749 boost::beast::http::field::warning,
750 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
751 "the value contained within HttpPushUri.\"");
752 handleUpdateServicePost(app, req, asyncResp);
753 });
754#endif
755 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
756 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700757 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700758 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700759}
760
761inline void requestRoutesSoftwareInventoryCollection(App& app)
762{
763 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700764 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700765 .methods(boost::beast::http::verb::get)(
766 [&app](const crow::Request& req,
767 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
768 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
769 {
770 return;
771 }
772 asyncResp->res.jsonValue["@odata.type"] =
773 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
774 asyncResp->res.jsonValue["@odata.id"] =
775 "/redfish/v1/UpdateService/FirmwareInventory";
776 asyncResp->res.jsonValue["Name"] =
777 "Software Inventory Collection";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700778
Ed Tanous14766872022-03-15 10:44:42 -0700779 crow::connections::systemBus->async_method_call(
780 [asyncResp](const boost::system::error_code ec,
781 const dbus::utility::MapperGetSubTreeResponse&
782 subtree) {
783 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700784 {
785 messages::internalError(asyncResp->res);
786 return;
787 }
Ed Tanous14766872022-03-15 10:44:42 -0700788 asyncResp->res.jsonValue["Members"] =
789 nlohmann::json::array();
790 asyncResp->res.jsonValue["Members@odata.count"] = 0;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700791
Ed Tanous14766872022-03-15 10:44:42 -0700792 for (const auto& obj : subtree)
793 {
794 sdbusplus::message::object_path path(obj.first);
795 std::string swId = path.filename();
796 if (swId.empty())
797 {
798 messages::internalError(asyncResp->res);
799 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
800 return;
801 }
802
803 nlohmann::json& members =
804 asyncResp->res.jsonValue["Members"];
805 nlohmann::json::object_t member;
806 member["@odata.id"] =
807 "/redfish/v1/UpdateService/FirmwareInventory/" +
808 swId;
809 members.push_back(std::move(member));
810 asyncResp->res.jsonValue["Members@odata.count"] =
811 members.size();
812 }
813 },
814 // Note that only firmware levels associated with a device
815 // are stored under /xyz/openbmc_project/software therefore
816 // to ensure only real FirmwareInventory items are returned,
817 // this full object path must be used here as input to
818 // mapper
819 "xyz.openbmc_project.ObjectMapper",
820 "/xyz/openbmc_project/object_mapper",
821 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
822 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
823 std::array<const char*, 1>{
824 "xyz.openbmc_project.Software.Version"});
825 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700826}
827/* Fill related item links (i.e. bmc, bios) in for inventory */
828inline static void
829 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
830 const std::string& purpose)
831{
832 if (purpose == fw_util::bmcPurpose)
833 {
834 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700835 nlohmann::json::object_t item;
836 item["@odata.id"] = "/redfish/v1/Managers/bmc";
837 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700838 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
839 }
840 else if (purpose == fw_util::biosPurpose)
841 {
842 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700843 nlohmann::json::object_t item;
844 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
845 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800846 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700847 }
848 else
849 {
850 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
851 }
852}
853
854inline void requestRoutesSoftwareInventory(App& app)
855{
856 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700857 .privileges(redfish::privileges::getSoftwareInventory)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700858 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700859 boost::beast::http::verb::
860 get)([&app](const crow::Request& req,
861 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
862 const std::string& param) {
863 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
864 {
865 return;
866 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700867 std::shared_ptr<std::string> swId =
868 std::make_shared<std::string>(param);
869
870 asyncResp->res.jsonValue["@odata.id"] =
871 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
872
873 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800874 [asyncResp,
875 swId](const boost::system::error_code ec,
876 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700877 BMCWEB_LOG_DEBUG << "doGet callback...";
878 if (ec)
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700879 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700880 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700881 return;
882 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700883
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700884 // Ensure we find our input swId, otherwise return an error
885 bool found = false;
886 for (const std::pair<
887 std::string,
888 std::vector<std::pair<
889 std::string, std::vector<std::string>>>>& obj :
890 subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800892 if (!boost::ends_with(obj.first, *swId))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700893 {
894 continue;
895 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896
Ed Tanous26f69762022-01-25 09:49:11 -0800897 if (obj.second.empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700898 {
899 continue;
900 }
901
902 found = true;
903 fw_util::getFwStatus(asyncResp, swId,
904 obj.second[0].first);
905
906 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -0800907 [asyncResp,
908 swId](const boost::system::error_code errorCode,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800909 const dbus::utility::DBusPropertiesMap&
Ed Tanous168e20c2021-12-13 14:39:53 -0800910 propertiesList) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700911 if (errorCode)
912 {
913 messages::internalError(asyncResp->res);
914 return;
915 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800916 const std::string* swInvPurpose = nullptr;
917 const std::string* version = nullptr;
918 for (const auto& property : propertiesList)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700919 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800920 if (property.first == "Purpose")
921 {
922 swInvPurpose = std::get_if<std::string>(
923 &property.second);
924 }
925 if (property.first == "Version")
926 {
927 version = std::get_if<std::string>(
928 &property.second);
929 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700930 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800931
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700932 if (swInvPurpose == nullptr)
933 {
George Liu0fda0f12021-11-16 10:06:17 +0800934 BMCWEB_LOG_DEBUG
Ed Tanousb9d36b42022-02-26 21:42:46 -0800935 << "Can't find property \"Purpose\"!";
936 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700937 return;
938 }
939
940 BMCWEB_LOG_DEBUG << "swInvPurpose = "
941 << *swInvPurpose;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700942
943 if (version == nullptr)
944 {
945 BMCWEB_LOG_DEBUG
946 << "Can't find property \"Version\"!";
947
Ed Tanousb9d36b42022-02-26 21:42:46 -0800948 messages::internalError(asyncResp->res);
949
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700950 return;
951 }
952 asyncResp->res.jsonValue["Version"] = *version;
953 asyncResp->res.jsonValue["Id"] = *swId;
954
955 // swInvPurpose is of format:
956 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
957 // Translate this to "ABC image"
958 size_t endDesc = swInvPurpose->rfind('.');
959 if (endDesc == std::string::npos)
960 {
961 messages::internalError(asyncResp->res);
962 return;
963 }
964 endDesc++;
965 if (endDesc >= swInvPurpose->size())
966 {
967 messages::internalError(asyncResp->res);
968 return;
969 }
970
971 std::string formatDesc =
972 swInvPurpose->substr(endDesc);
973 asyncResp->res.jsonValue["Description"] =
974 formatDesc + " image";
975 getRelatedItems(asyncResp, *swInvPurpose);
976 },
977 obj.second[0].first, obj.first,
978 "org.freedesktop.DBus.Properties", "GetAll",
979 "xyz.openbmc_project.Software.Version");
980 }
981 if (!found)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800983 BMCWEB_LOG_ERROR << "Input swID " << *swId
984 << " not found!";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700985 messages::resourceMissingAtURI(
986 asyncResp->res,
Ed Tanousace85d62021-10-26 12:45:59 -0700987 crow::utility::urlFromPieces(
988 "redfish", "v1", "UpdateService",
989 "FirmwareInventory", *swId));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700990 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700992 asyncResp->res.jsonValue["@odata.type"] =
993 "#SoftwareInventory.v1_1_0.SoftwareInventory";
994 asyncResp->res.jsonValue["Name"] = "Software Inventory";
995 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700997 asyncResp->res.jsonValue["Updateable"] = false;
998 fw_util::getFwUpdateableStatus(asyncResp, swId);
999 },
1000 "xyz.openbmc_project.ObjectMapper",
1001 "/xyz/openbmc_project/object_mapper",
1002 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
1003 static_cast<int32_t>(0),
1004 std::array<const char*, 1>{
1005 "xyz.openbmc_project.Software.Version"});
1006 });
1007}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008
1009} // namespace redfish