blob: 53ee1ad3be01cbece8d2870a7b5f68f7428de280 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700584 asyncResp->res.jsonValue["HttpPushUri"] =
Ed Tanous4dc23f32022-05-11 11:32:19 -0700585 "/redfish/v1/UpdateService/update";
586
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700587 // UpdateService cannot be disabled
588 asyncResp->res.jsonValue["ServiceEnabled"] = true;
Ed Tanous14766872022-03-15 10:44:42 -0700589 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
590 "/redfish/v1/UpdateService/FirmwareInventory";
Tejas Patild61e5192021-06-04 15:49:35 +0530591 // Get the MaxImageSizeBytes
592 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
593 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
594
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700595#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
596 // Update Actions object.
597 nlohmann::json& updateSvcSimpleUpdate =
598 asyncResp->res
599 .jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
600 updateSvcSimpleUpdate["target"] =
601 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
602 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
603 {"TFTP"};
604#endif
605 // Get the current ApplyTime value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700606 sdbusplus::asio::getProperty<std::string>(
607 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
608 "/xyz/openbmc_project/software/apply_time",
609 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700610 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700611 const std::string& applyTime) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700612 if (ec)
613 {
614 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
615 messages::internalError(asyncResp->res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530616 return;
617 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530618
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700619 // Store the ApplyTime Value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700620 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
621 "RequestedApplyTimes.Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700622 {
623 asyncResp->res
624 .jsonValue["HttpPushUriOptions"]
625 ["HttpPushUriApplyTime"]["ApplyTime"] =
626 "Immediate";
627 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700628 else if (applyTime ==
629 "xyz.openbmc_project.Software.ApplyTime."
630 "RequestedApplyTimes.OnReset")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700631 {
632 asyncResp->res
633 .jsonValue["HttpPushUriOptions"]
634 ["HttpPushUriApplyTime"]["ApplyTime"] =
635 "OnReset";
636 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700637 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700638 });
639 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700640 .privileges(redfish::privileges::patchUpdateService)
George Liu0fda0f12021-11-16 10:06:17 +0800641 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700642 boost::beast::http::verb::patch)([&app](const crow::Request& req,
643 const std::shared_ptr<
644 bmcweb::AsyncResp>&
645 asyncResp) {
646 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
647 {
648 return;
649 }
George Liu0fda0f12021-11-16 10:06:17 +0800650 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530651
George Liu0fda0f12021-11-16 10:06:17 +0800652 std::optional<nlohmann::json> pushUriOptions;
Willy Tu15ed6782021-12-14 11:03:16 -0800653 if (!json_util::readJsonPatch(req, asyncResp->res,
654 "HttpPushUriOptions", pushUriOptions))
George Liu0fda0f12021-11-16 10:06:17 +0800655 {
656 return;
657 }
658
659 if (pushUriOptions)
660 {
661 std::optional<nlohmann::json> pushUriApplyTime;
662 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
663 "HttpPushUriApplyTime",
664 pushUriApplyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700666 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700668
George Liu0fda0f12021-11-16 10:06:17 +0800669 if (pushUriApplyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
George Liu0fda0f12021-11-16 10:06:17 +0800671 std::optional<std::string> applyTime;
672 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
673 "ApplyTime", applyTime))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700674 {
675 return;
676 }
677
George Liu0fda0f12021-11-16 10:06:17 +0800678 if (applyTime)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700679 {
George Liu0fda0f12021-11-16 10:06:17 +0800680 std::string applyTimeNewVal;
681 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700682 {
George Liu0fda0f12021-11-16 10:06:17 +0800683 applyTimeNewVal =
684 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
685 }
686 else if (applyTime == "OnReset")
687 {
688 applyTimeNewVal =
689 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
690 }
691 else
692 {
693 BMCWEB_LOG_INFO
694 << "ApplyTime value is not in the list of acceptable values";
695 messages::propertyValueNotInList(
696 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700697 return;
698 }
699
George Liu0fda0f12021-11-16 10:06:17 +0800700 // Set the requested image apply time value
701 crow::connections::systemBus->async_method_call(
702 [asyncResp](const boost::system::error_code ec) {
703 if (ec)
704 {
705 BMCWEB_LOG_ERROR
706 << "D-Bus responses error: " << ec;
707 messages::internalError(asyncResp->res);
708 return;
709 }
710 messages::success(asyncResp->res);
711 },
712 "xyz.openbmc_project.Settings",
713 "/xyz/openbmc_project/software/apply_time",
714 "org.freedesktop.DBus.Properties", "Set",
715 "xyz.openbmc_project.Software.ApplyTime",
716 "RequestedApplyTime",
Ed Tanous168e20c2021-12-13 14:39:53 -0800717 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700718 }
719 }
George Liu0fda0f12021-11-16 10:06:17 +0800720 }
721 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700722
Ed Tanous4dc23f32022-05-11 11:32:19 -0700723// The "old" behavior of the update service URI causes redfish-service validator
724// failures when the Allow header is supported, given that in the spec,
725// UpdateService does not allow POST. in openbmc, we unfortunately reused that
726// resource as our HttpPushUri as well. A number of services, including the
727// openbmc tests, and documentation have hardcoded that erroneous API, instead
728// of relying on HttpPushUri as the spec requires. This option will exist
729// temporarily to allow the old behavior until Q4 2022, at which time it will be
730// removed.
731#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700732 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700733 .privileges(redfish::privileges::postUpdateService)
Ed Tanous4dc23f32022-05-11 11:32:19 -0700734 .methods(
735 boost::beast::http::verb::
736 post)([&app](
737 const crow::Request& req,
738 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
739 asyncResp->res.addHeader(
740 boost::beast::http::field::warning,
741 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
742 "the value contained within HttpPushUri.\"");
743 handleUpdateServicePost(app, req, asyncResp);
744 });
745#endif
746 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
747 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700748 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700749 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700750}
751
752inline void requestRoutesSoftwareInventoryCollection(App& app)
753{
754 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700755 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700756 .methods(boost::beast::http::verb::get)(
757 [&app](const crow::Request& req,
758 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
759 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
760 {
761 return;
762 }
763 asyncResp->res.jsonValue["@odata.type"] =
764 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
765 asyncResp->res.jsonValue["@odata.id"] =
766 "/redfish/v1/UpdateService/FirmwareInventory";
767 asyncResp->res.jsonValue["Name"] =
768 "Software Inventory Collection";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700769
Ed Tanous14766872022-03-15 10:44:42 -0700770 crow::connections::systemBus->async_method_call(
771 [asyncResp](const boost::system::error_code ec,
772 const dbus::utility::MapperGetSubTreeResponse&
773 subtree) {
774 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700775 {
776 messages::internalError(asyncResp->res);
777 return;
778 }
Ed Tanous14766872022-03-15 10:44:42 -0700779 asyncResp->res.jsonValue["Members"] =
780 nlohmann::json::array();
781 asyncResp->res.jsonValue["Members@odata.count"] = 0;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700782
Ed Tanous14766872022-03-15 10:44:42 -0700783 for (const auto& obj : subtree)
784 {
785 sdbusplus::message::object_path path(obj.first);
786 std::string swId = path.filename();
787 if (swId.empty())
788 {
789 messages::internalError(asyncResp->res);
790 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
791 return;
792 }
793
794 nlohmann::json& members =
795 asyncResp->res.jsonValue["Members"];
796 nlohmann::json::object_t member;
797 member["@odata.id"] =
798 "/redfish/v1/UpdateService/FirmwareInventory/" +
799 swId;
800 members.push_back(std::move(member));
801 asyncResp->res.jsonValue["Members@odata.count"] =
802 members.size();
803 }
804 },
805 // Note that only firmware levels associated with a device
806 // are stored under /xyz/openbmc_project/software therefore
807 // to ensure only real FirmwareInventory items are returned,
808 // this full object path must be used here as input to
809 // mapper
810 "xyz.openbmc_project.ObjectMapper",
811 "/xyz/openbmc_project/object_mapper",
812 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
813 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
814 std::array<const char*, 1>{
815 "xyz.openbmc_project.Software.Version"});
816 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700817}
818/* Fill related item links (i.e. bmc, bios) in for inventory */
819inline static void
820 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
821 const std::string& purpose)
822{
823 if (purpose == fw_util::bmcPurpose)
824 {
825 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700826 nlohmann::json::object_t item;
827 item["@odata.id"] = "/redfish/v1/Managers/bmc";
828 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700829 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
830 }
831 else if (purpose == fw_util::biosPurpose)
832 {
833 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700834 nlohmann::json::object_t item;
835 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
836 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800837 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700838 }
839 else
840 {
841 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
842 }
843}
844
845inline void requestRoutesSoftwareInventory(App& app)
846{
847 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700848 .privileges(redfish::privileges::getSoftwareInventory)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700849 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700850 boost::beast::http::verb::
851 get)([&app](const crow::Request& req,
852 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
853 const std::string& param) {
854 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
855 {
856 return;
857 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700858 std::shared_ptr<std::string> swId =
859 std::make_shared<std::string>(param);
860
861 asyncResp->res.jsonValue["@odata.id"] =
862 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
863
864 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800865 [asyncResp,
866 swId](const boost::system::error_code ec,
867 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700868 BMCWEB_LOG_DEBUG << "doGet callback...";
869 if (ec)
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700870 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700871 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700872 return;
873 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700874
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700875 // Ensure we find our input swId, otherwise return an error
876 bool found = false;
877 for (const std::pair<
878 std::string,
879 std::vector<std::pair<
880 std::string, std::vector<std::string>>>>& obj :
881 subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800883 if (!boost::ends_with(obj.first, *swId))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700884 {
885 continue;
886 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887
Ed Tanous26f69762022-01-25 09:49:11 -0800888 if (obj.second.empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700889 {
890 continue;
891 }
892
893 found = true;
894 fw_util::getFwStatus(asyncResp, swId,
895 obj.second[0].first);
896
897 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -0800898 [asyncResp,
899 swId](const boost::system::error_code errorCode,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800900 const dbus::utility::DBusPropertiesMap&
Ed Tanous168e20c2021-12-13 14:39:53 -0800901 propertiesList) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700902 if (errorCode)
903 {
904 messages::internalError(asyncResp->res);
905 return;
906 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800907 const std::string* swInvPurpose = nullptr;
908 const std::string* version = nullptr;
909 for (const auto& property : propertiesList)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700910 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800911 if (property.first == "Purpose")
912 {
913 swInvPurpose = std::get_if<std::string>(
914 &property.second);
915 }
916 if (property.first == "Version")
917 {
918 version = std::get_if<std::string>(
919 &property.second);
920 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700921 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800922
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700923 if (swInvPurpose == nullptr)
924 {
George Liu0fda0f12021-11-16 10:06:17 +0800925 BMCWEB_LOG_DEBUG
Ed Tanousb9d36b42022-02-26 21:42:46 -0800926 << "Can't find property \"Purpose\"!";
927 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700928 return;
929 }
930
931 BMCWEB_LOG_DEBUG << "swInvPurpose = "
932 << *swInvPurpose;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700933
934 if (version == nullptr)
935 {
936 BMCWEB_LOG_DEBUG
937 << "Can't find property \"Version\"!";
938
Ed Tanousb9d36b42022-02-26 21:42:46 -0800939 messages::internalError(asyncResp->res);
940
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700941 return;
942 }
943 asyncResp->res.jsonValue["Version"] = *version;
944 asyncResp->res.jsonValue["Id"] = *swId;
945
946 // swInvPurpose is of format:
947 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
948 // Translate this to "ABC image"
949 size_t endDesc = swInvPurpose->rfind('.');
950 if (endDesc == std::string::npos)
951 {
952 messages::internalError(asyncResp->res);
953 return;
954 }
955 endDesc++;
956 if (endDesc >= swInvPurpose->size())
957 {
958 messages::internalError(asyncResp->res);
959 return;
960 }
961
962 std::string formatDesc =
963 swInvPurpose->substr(endDesc);
964 asyncResp->res.jsonValue["Description"] =
965 formatDesc + " image";
966 getRelatedItems(asyncResp, *swInvPurpose);
967 },
968 obj.second[0].first, obj.first,
969 "org.freedesktop.DBus.Properties", "GetAll",
970 "xyz.openbmc_project.Software.Version");
971 }
972 if (!found)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800974 BMCWEB_LOG_ERROR << "Input swID " << *swId
975 << " not found!";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700976 messages::resourceMissingAtURI(
977 asyncResp->res,
Ed Tanousace85d62021-10-26 12:45:59 -0700978 crow::utility::urlFromPieces(
979 "redfish", "v1", "UpdateService",
980 "FirmwareInventory", *swId));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700981 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700983 asyncResp->res.jsonValue["@odata.type"] =
984 "#SoftwareInventory.v1_1_0.SoftwareInventory";
985 asyncResp->res.jsonValue["Name"] = "Software Inventory";
986 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700988 asyncResp->res.jsonValue["Updateable"] = false;
989 fw_util::getFwUpdateableStatus(asyncResp, swId);
990 },
991 "xyz.openbmc_project.ObjectMapper",
992 "/xyz/openbmc_project/object_mapper",
993 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
994 static_cast<int32_t>(0),
995 std::array<const char*, 1>{
996 "xyz.openbmc_project.Software.Version"});
997 });
998}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999
1000} // namespace redfish