blob: 70fe8dbd203ec2e241d26345778c162e5ea76993 [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
540inline void requestRoutesUpdateService(App& app)
541{
542 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700543 .privileges(redfish::privileges::getUpdateService)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700544 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
545 const std::shared_ptr<
546 bmcweb::AsyncResp>&
547 asyncResp) {
548 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
549 {
550 return;
551 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700552 asyncResp->res.jsonValue["@odata.type"] =
Chicago Duan0588a3b2021-06-10 18:20:36 +0800553 "#UpdateService.v1_5_0.UpdateService";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700554 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
555 asyncResp->res.jsonValue["Id"] = "UpdateService";
556 asyncResp->res.jsonValue["Description"] =
557 "Service for Software Update";
558 asyncResp->res.jsonValue["Name"] = "Update Service";
559 asyncResp->res.jsonValue["HttpPushUri"] =
560 "/redfish/v1/UpdateService";
561 // UpdateService cannot be disabled
562 asyncResp->res.jsonValue["ServiceEnabled"] = true;
563 asyncResp->res.jsonValue["FirmwareInventory"] = {
564 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Tejas Patild61e5192021-06-04 15:49:35 +0530565 // Get the MaxImageSizeBytes
566 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
567 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
568
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700569#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
570 // Update Actions object.
571 nlohmann::json& updateSvcSimpleUpdate =
572 asyncResp->res
573 .jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
574 updateSvcSimpleUpdate["target"] =
575 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
576 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
577 {"TFTP"};
578#endif
579 // Get the current ApplyTime value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700580 sdbusplus::asio::getProperty<std::string>(
581 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
582 "/xyz/openbmc_project/software/apply_time",
583 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700584 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700585 const std::string& applyTime) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700586 if (ec)
587 {
588 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
589 messages::internalError(asyncResp->res);
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530590 return;
591 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530592
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700593 // Store the ApplyTime Value
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700594 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
595 "RequestedApplyTimes.Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700596 {
597 asyncResp->res
598 .jsonValue["HttpPushUriOptions"]
599 ["HttpPushUriApplyTime"]["ApplyTime"] =
600 "Immediate";
601 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700602 else if (applyTime ==
603 "xyz.openbmc_project.Software.ApplyTime."
604 "RequestedApplyTimes.OnReset")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700605 {
606 asyncResp->res
607 .jsonValue["HttpPushUriOptions"]
608 ["HttpPushUriApplyTime"]["ApplyTime"] =
609 "OnReset";
610 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700611 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700612 });
613 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700614 .privileges(redfish::privileges::patchUpdateService)
George Liu0fda0f12021-11-16 10:06:17 +0800615 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700616 boost::beast::http::verb::patch)([&app](const crow::Request& req,
617 const std::shared_ptr<
618 bmcweb::AsyncResp>&
619 asyncResp) {
620 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
621 {
622 return;
623 }
George Liu0fda0f12021-11-16 10:06:17 +0800624 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530625
George Liu0fda0f12021-11-16 10:06:17 +0800626 std::optional<nlohmann::json> pushUriOptions;
Willy Tu15ed6782021-12-14 11:03:16 -0800627 if (!json_util::readJsonPatch(req, asyncResp->res,
628 "HttpPushUriOptions", pushUriOptions))
George Liu0fda0f12021-11-16 10:06:17 +0800629 {
630 return;
631 }
632
633 if (pushUriOptions)
634 {
635 std::optional<nlohmann::json> pushUriApplyTime;
636 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
637 "HttpPushUriApplyTime",
638 pushUriApplyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700640 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700642
George Liu0fda0f12021-11-16 10:06:17 +0800643 if (pushUriApplyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 {
George Liu0fda0f12021-11-16 10:06:17 +0800645 std::optional<std::string> applyTime;
646 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
647 "ApplyTime", applyTime))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700648 {
649 return;
650 }
651
George Liu0fda0f12021-11-16 10:06:17 +0800652 if (applyTime)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700653 {
George Liu0fda0f12021-11-16 10:06:17 +0800654 std::string applyTimeNewVal;
655 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700656 {
George Liu0fda0f12021-11-16 10:06:17 +0800657 applyTimeNewVal =
658 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
659 }
660 else if (applyTime == "OnReset")
661 {
662 applyTimeNewVal =
663 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
664 }
665 else
666 {
667 BMCWEB_LOG_INFO
668 << "ApplyTime value is not in the list of acceptable values";
669 messages::propertyValueNotInList(
670 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700671 return;
672 }
673
George Liu0fda0f12021-11-16 10:06:17 +0800674 // Set the requested image apply time value
675 crow::connections::systemBus->async_method_call(
676 [asyncResp](const boost::system::error_code ec) {
677 if (ec)
678 {
679 BMCWEB_LOG_ERROR
680 << "D-Bus responses error: " << ec;
681 messages::internalError(asyncResp->res);
682 return;
683 }
684 messages::success(asyncResp->res);
685 },
686 "xyz.openbmc_project.Settings",
687 "/xyz/openbmc_project/software/apply_time",
688 "org.freedesktop.DBus.Properties", "Set",
689 "xyz.openbmc_project.Software.ApplyTime",
690 "RequestedApplyTime",
Ed Tanous168e20c2021-12-13 14:39:53 -0800691 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700692 }
693 }
George Liu0fda0f12021-11-16 10:06:17 +0800694 }
695 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700696 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700697 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700698 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700699 [&app](const crow::Request& req,
700 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
701 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
702 {
703 return;
704 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700705 BMCWEB_LOG_DEBUG << "doPost...";
706
707 // Setup callback for when new software detected
708 monitorForSoftwareAvailable(asyncResp, req,
709 "/redfish/v1/UpdateService");
710
711 std::string filepath("/tmp/images/" +
712 boost::uuids::to_string(
713 boost::uuids::random_generator()()));
714 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
715 std::ofstream out(filepath, std::ofstream::out |
716 std::ofstream::binary |
717 std::ofstream::trunc);
718 out << req.body;
719 out.close();
720 BMCWEB_LOG_DEBUG << "file upload complete!!";
721 });
722}
723
724inline void requestRoutesSoftwareInventoryCollection(App& app)
725{
726 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700727 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700728 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
729 const std::shared_ptr<
730 bmcweb::AsyncResp>&
731 asyncResp) {
732 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
733 {
734 return;
735 }
George Liu0fda0f12021-11-16 10:06:17 +0800736 asyncResp->res.jsonValue["@odata.type"] =
737 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
738 asyncResp->res.jsonValue["@odata.id"] =
739 "/redfish/v1/UpdateService/FirmwareInventory";
740 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700741
George Liu0fda0f12021-11-16 10:06:17 +0800742 crow::connections::systemBus->async_method_call(
743 [asyncResp](
744 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800745 const dbus::utility::MapperGetSubTreeResponse& subtree) {
George Liu0fda0f12021-11-16 10:06:17 +0800746 if (ec)
747 {
748 messages::internalError(asyncResp->res);
749 return;
750 }
751 asyncResp->res.jsonValue["Members"] =
752 nlohmann::json::array();
753 asyncResp->res.jsonValue["Members@odata.count"] = 0;
754
Ed Tanous9eb808c2022-01-25 10:19:23 -0800755 for (const auto& obj : subtree)
George Liu0fda0f12021-11-16 10:06:17 +0800756 {
757 sdbusplus::message::object_path path(obj.first);
758 std::string swId = path.filename();
759 if (swId.empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700760 {
761 messages::internalError(asyncResp->res);
George Liu0fda0f12021-11-16 10:06:17 +0800762 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700763 return;
764 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700765
George Liu0fda0f12021-11-16 10:06:17 +0800766 nlohmann::json& members =
767 asyncResp->res.jsonValue["Members"];
768 members.push_back(
769 {{"@odata.id",
770 "/redfish/v1/UpdateService/FirmwareInventory/" +
771 swId}});
772 asyncResp->res.jsonValue["Members@odata.count"] =
773 members.size();
774 }
775 },
776 // Note that only firmware levels associated with a device
777 // are stored under /xyz/openbmc_project/software therefore
778 // to ensure only real FirmwareInventory items are returned,
779 // this full object path must be used here as input to
780 // mapper
781 "xyz.openbmc_project.ObjectMapper",
782 "/xyz/openbmc_project/object_mapper",
783 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
784 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
785 std::array<const char*, 1>{
786 "xyz.openbmc_project.Software.Version"});
787 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700788}
789/* Fill related item links (i.e. bmc, bios) in for inventory */
790inline static void
791 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
792 const std::string& purpose)
793{
794 if (purpose == fw_util::bmcPurpose)
795 {
796 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
797 relatedItem.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
798 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
799 }
800 else if (purpose == fw_util::biosPurpose)
801 {
802 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
803 relatedItem.push_back(
804 {{"@odata.id", "/redfish/v1/Systems/system/Bios"}});
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800805 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700806 }
807 else
808 {
809 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
810 }
811}
812
813inline void requestRoutesSoftwareInventory(App& app)
814{
815 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700816 .privileges(redfish::privileges::getSoftwareInventory)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700817 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700818 boost::beast::http::verb::
819 get)([&app](const crow::Request& req,
820 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
821 const std::string& param) {
822 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
823 {
824 return;
825 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700826 std::shared_ptr<std::string> swId =
827 std::make_shared<std::string>(param);
828
829 asyncResp->res.jsonValue["@odata.id"] =
830 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
831
832 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800833 [asyncResp,
834 swId](const boost::system::error_code ec,
835 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700836 BMCWEB_LOG_DEBUG << "doGet callback...";
837 if (ec)
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700838 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700839 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700840 return;
841 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700842
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700843 // Ensure we find our input swId, otherwise return an error
844 bool found = false;
845 for (const std::pair<
846 std::string,
847 std::vector<std::pair<
848 std::string, std::vector<std::string>>>>& obj :
849 subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800851 if (!boost::ends_with(obj.first, *swId))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700852 {
853 continue;
854 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855
Ed Tanous26f69762022-01-25 09:49:11 -0800856 if (obj.second.empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700857 {
858 continue;
859 }
860
861 found = true;
862 fw_util::getFwStatus(asyncResp, swId,
863 obj.second[0].first);
864
865 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -0800866 [asyncResp,
867 swId](const boost::system::error_code errorCode,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800868 const dbus::utility::DBusPropertiesMap&
Ed Tanous168e20c2021-12-13 14:39:53 -0800869 propertiesList) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700870 if (errorCode)
871 {
872 messages::internalError(asyncResp->res);
873 return;
874 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800875 const std::string* swInvPurpose = nullptr;
876 const std::string* version = nullptr;
877 for (const auto& property : propertiesList)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700878 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800879 if (property.first == "Purpose")
880 {
881 swInvPurpose = std::get_if<std::string>(
882 &property.second);
883 }
884 if (property.first == "Version")
885 {
886 version = std::get_if<std::string>(
887 &property.second);
888 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700889 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800890
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700891 if (swInvPurpose == nullptr)
892 {
George Liu0fda0f12021-11-16 10:06:17 +0800893 BMCWEB_LOG_DEBUG
Ed Tanousb9d36b42022-02-26 21:42:46 -0800894 << "Can't find property \"Purpose\"!";
895 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700896 return;
897 }
898
899 BMCWEB_LOG_DEBUG << "swInvPurpose = "
900 << *swInvPurpose;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700901
902 if (version == nullptr)
903 {
904 BMCWEB_LOG_DEBUG
905 << "Can't find property \"Version\"!";
906
Ed Tanousb9d36b42022-02-26 21:42:46 -0800907 messages::internalError(asyncResp->res);
908
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700909 return;
910 }
911 asyncResp->res.jsonValue["Version"] = *version;
912 asyncResp->res.jsonValue["Id"] = *swId;
913
914 // swInvPurpose is of format:
915 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
916 // Translate this to "ABC image"
917 size_t endDesc = swInvPurpose->rfind('.');
918 if (endDesc == std::string::npos)
919 {
920 messages::internalError(asyncResp->res);
921 return;
922 }
923 endDesc++;
924 if (endDesc >= swInvPurpose->size())
925 {
926 messages::internalError(asyncResp->res);
927 return;
928 }
929
930 std::string formatDesc =
931 swInvPurpose->substr(endDesc);
932 asyncResp->res.jsonValue["Description"] =
933 formatDesc + " image";
934 getRelatedItems(asyncResp, *swInvPurpose);
935 },
936 obj.second[0].first, obj.first,
937 "org.freedesktop.DBus.Properties", "GetAll",
938 "xyz.openbmc_project.Software.Version");
939 }
940 if (!found)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700941 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800942 BMCWEB_LOG_ERROR << "Input swID " << *swId
943 << " not found!";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700944 messages::resourceMissingAtURI(
945 asyncResp->res,
Ed Tanousace85d62021-10-26 12:45:59 -0700946 crow::utility::urlFromPieces(
947 "redfish", "v1", "UpdateService",
948 "FirmwareInventory", *swId));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700949 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700951 asyncResp->res.jsonValue["@odata.type"] =
952 "#SoftwareInventory.v1_1_0.SoftwareInventory";
953 asyncResp->res.jsonValue["Name"] = "Software Inventory";
954 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700956 asyncResp->res.jsonValue["Updateable"] = false;
957 fw_util::getFwUpdateableStatus(asyncResp, swId);
958 },
959 "xyz.openbmc_project.ObjectMapper",
960 "/xyz/openbmc_project/object_mapper",
961 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
962 static_cast<int32_t>(0),
963 std::array<const char*, 1>{
964 "xyz.openbmc_project.Software.Version"});
965 });
966}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967
968} // namespace redfish