blob: 6cf15d61501723e3863c835fd78f117add4cde6a [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>
Willy Tueee00132022-06-14 14:53:17 -070025#include <utils/sw_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
Patrick Williams59d494e2022-07-22 19:26:55 -050031static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
32static std::unique_ptr<sdbusplus::bus::match_t> 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) {
Ed Tanous002d39b2022-05-31 08:59:27 -070050 if (errorCode)
51 {
52 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
53 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
54 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050055 },
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,
Patrick Williams59d494e2022-07-22 19:26:55 -050066 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -050067{
Ed Tanousb9d36b42022-02-26 21:42:46 -080068 dbus::utility::DBusInteracesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -050069
70 sdbusplus::message::object_path objPath;
71
72 m.read(objPath, interfacesProperties);
73
74 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050075 for (auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050076 {
77 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
78
79 if (interface.first == "xyz.openbmc_project.Software.Activation")
80 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050081 // Retrieve service and activate
82 crow::connections::systemBus->async_method_call(
Ed Tanousa3e65892021-09-16 14:13:20 -070083 [objPath, asyncResp, payload(std::move(payload))](
84 const boost::system::error_code errorCode,
85 const std::vector<
86 std::pair<std::string, std::vector<std::string>>>&
87 objInfo) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -070088 if (errorCode)
89 {
90 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
91 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050092 if (asyncResp)
93 {
Ed Tanous002d39b2022-05-31 08:59:27 -070094 messages::internalError(asyncResp->res);
95 }
96 cleanUp();
97 return;
98 }
99 // Ensure we only got one service back
100 if (objInfo.size() != 1)
101 {
102 BMCWEB_LOG_ERROR << "Invalid Object Size "
103 << objInfo.size();
104 if (asyncResp)
105 {
106 messages::internalError(asyncResp->res);
107 }
108 cleanUp();
109 return;
110 }
111 // cancel timer only when
112 // xyz.openbmc_project.Software.Activation interface
113 // is added
114 fwAvailableTimer = nullptr;
115
116 activateImage(objPath.str, objInfo[0].first);
117 if (asyncResp)
118 {
119 std::shared_ptr<task::TaskData> task =
120 task::TaskData::createTask(
121 [](boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500122 sdbusplus::message_t& msg,
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 const std::shared_ptr<task::TaskData>&
124 taskData) {
125 if (ec)
126 {
127 return task::completed;
128 }
129
130 std::string iface;
131 dbus::utility::DBusPropertiesMap values;
132
133 std::string index = std::to_string(taskData->index);
134 msg.read(iface, values);
135
136 if (iface == "xyz.openbmc_project.Software.Activation")
137 {
138 std::string* state = nullptr;
139 for (const auto& property : values)
140 {
141 if (property.first == "Activation")
142 {
Ed Tanous8a592812022-06-04 09:06:59 -0700143 const std::string* activationState =
Ed Tanous002d39b2022-05-31 08:59:27 -0700144 std::get_if<std::string>(
145 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700146 if (activationState == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700147 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 taskData->messages.emplace_back(
149 messages::internalError());
James Feist32898ce2020-03-10 16:16:52 -0700150 return task::completed;
151 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700152 }
153 }
James Feist32898ce2020-03-10 16:16:52 -0700154
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 if (state == nullptr)
156 {
157 return !task::completed;
158 }
James Feist32898ce2020-03-10 16:16:52 -0700159
Ed Tanous11ba3972022-07-11 09:50:41 -0700160 if (state->ends_with("Invalid") ||
161 state->ends_with("Failed"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 {
163 taskData->state = "Exception";
164 taskData->status = "Warning";
165 taskData->messages.emplace_back(
166 messages::taskAborted(index));
167 return task::completed;
168 }
James Feiste5d50062020-05-11 17:29:00 -0700169
Ed Tanous11ba3972022-07-11 09:50:41 -0700170 if (state->ends_with("Staged"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700171 {
172 taskData->state = "Stopping";
173 taskData->messages.emplace_back(
174 messages::taskPaused(index));
175
176 // its staged, set a long timer to
177 // allow them time to complete the
178 // update (probably cycle the
179 // system) if this expires then
180 // task will be cancelled
181 taskData->extendTimer(std::chrono::hours(5));
182 return !task::completed;
183 }
184
Ed Tanous11ba3972022-07-11 09:50:41 -0700185 if (state->ends_with("Active"))
Ed Tanous002d39b2022-05-31 08:59:27 -0700186 {
187 taskData->messages.emplace_back(
188 messages::taskCompletedOK(index));
189 taskData->state = "Completed";
190 return task::completed;
191 }
192 }
193 else if (
194 iface ==
195 "xyz.openbmc_project.Software.ActivationProgress")
196 {
197
198 const uint8_t* progress = nullptr;
199 for (const auto& property : values)
200 {
201 if (property.first == "Progress")
202 {
Ed Tanous8a592812022-06-04 09:06:59 -0700203 const std::string* progressStr =
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 std::get_if<std::string>(
205 &property.second);
Ed Tanous8a592812022-06-04 09:06:59 -0700206 if (progressStr == nullptr)
James Feist32898ce2020-03-10 16:16:52 -0700207 {
James Feist32898ce2020-03-10 16:16:52 -0700208 taskData->messages.emplace_back(
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 messages::internalError());
210 return task::completed;
James Feist32898ce2020-03-10 16:16:52 -0700211 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700212 }
213 }
James Feist32898ce2020-03-10 16:16:52 -0700214
Ed Tanous002d39b2022-05-31 08:59:27 -0700215 if (progress == nullptr)
216 {
217 return !task::completed;
218 }
219 taskData->percentComplete =
220 static_cast<int>(*progress);
221 taskData->messages.emplace_back(
222 messages::taskProgressChanged(
223 index, static_cast<size_t>(*progress)));
James Feist32898ce2020-03-10 16:16:52 -0700224
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 // if we're getting status updates it's
226 // still alive, update timer
227 taskData->extendTimer(std::chrono::minutes(5));
228 }
229
230 // as firmware update often results in a
231 // reboot, the task may never "complete"
232 // unless it is an error
233
234 return !task::completed;
235 },
236 "type='signal',interface='org.freedesktop.DBus.Properties',"
237 "member='PropertiesChanged',path='" +
238 objPath.str + "'");
239 task->startTimer(std::chrono::minutes(5));
240 task->populateResp(asyncResp->res);
241 task->payload.emplace(std::move(payload));
242 }
243 fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500244 },
245 "xyz.openbmc_project.ObjectMapper",
246 "/xyz/openbmc_project/object_mapper",
247 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500249 "xyz.openbmc_project.Software.Activation"});
250 }
251 }
252}
253
Andrew Geissler0554c982019-04-23 14:40:12 -0500254// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
255// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700256static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800257 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
258 const crow::Request& req, const std::string& url,
259 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500260{
261 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800262 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500264 if (asyncResp)
265 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500266 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
267 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500268 return;
269 }
270
Andrew Geissler0554c982019-04-23 14:40:12 -0500271 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700272 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500273
Ed Tanous271584a2019-07-09 16:24:22 -0700274 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500275
276 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700278 cleanUp();
279 if (ec == boost::asio::error::operation_aborted)
280 {
281 // expected, we were canceled before the timer completed.
282 return;
283 }
284 BMCWEB_LOG_ERROR
285 << "Timed out waiting for firmware object being created";
286 BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
287 if (ec)
288 {
289 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
290 return;
291 }
292 if (asyncResp)
293 {
294 redfish::messages::internalError(asyncResp->res);
295 }
296 });
Ed Tanousa3e65892021-09-16 14:13:20 -0700297 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500298 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500299 BMCWEB_LOG_DEBUG << "Match fired";
Ed Tanousa3e65892021-09-16 14:13:20 -0700300 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500301 };
302
303 fwUpdateInProgress = true;
304
Patrick Williams59d494e2022-07-22 19:26:55 -0500305 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500306 *crow::connections::systemBus,
307 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
308 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
309 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700310
Patrick Williams59d494e2022-07-22 19:26:55 -0500311 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700312 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800313 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
314 "member='InterfacesAdded',"
315 "path='/xyz/openbmc_project/logging'",
Patrick Williams59d494e2022-07-22 19:26:55 -0500316 [asyncResp, url](sdbusplus::message_t& m) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 std::vector<std::pair<std::string, dbus::utility::DBusPropertiesMap>>
318 interfacesProperties;
319 sdbusplus::message::object_path objPath;
320 m.read(objPath, interfacesProperties);
321 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
322 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
323 interface : interfacesProperties)
324 {
325 if (interface.first == "xyz.openbmc_project.Logging.Entry")
James Feist4cde5d92020-06-11 10:39:55 -0700326 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 for (const std::pair<std::string,
328 dbus::utility::DbusVariantType>& value :
329 interface.second)
Brian Mae1cc4822021-12-01 17:05:54 +0800330 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 if (value.first != "Message")
Brian Mae1cc4822021-12-01 17:05:54 +0800332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 continue;
334 }
335 const std::string* type =
336 std::get_if<std::string>(&value.second);
337 if (type == nullptr)
338 {
339 // if this was our message, timeout will cover it
340 return;
341 }
342 fwAvailableTimer = nullptr;
343 if (*type ==
344 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
345 {
346 redfish::messages::invalidUpload(asyncResp->res, url,
347 "Invalid archive");
348 }
349 else if (*type ==
350 "xyz.openbmc_project.Software.Image.Error."
351 "ManifestFileFailure")
352 {
353 redfish::messages::invalidUpload(asyncResp->res, url,
354 "Invalid manifest");
355 }
356 else if (
357 *type ==
358 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
359 {
360 redfish::messages::invalidUpload(
361 asyncResp->res, url, "Invalid image format");
362 }
363 else if (
364 *type ==
365 "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
366 {
367 redfish::messages::invalidUpload(
368 asyncResp->res, url,
369 "Image version already exists");
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600370
Ed Tanous002d39b2022-05-31 08:59:27 -0700371 redfish::messages::resourceAlreadyExists(
372 asyncResp->res,
373 "UpdateService.v1_5_0.UpdateService", "Version",
374 "uploaded version");
375 }
376 else if (
377 *type ==
378 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
379 {
380 redfish::messages::resourceExhaustion(asyncResp->res,
381 url);
382 }
383 else
384 {
385 redfish::messages::internalError(asyncResp->res);
Brian Mae1cc4822021-12-01 17:05:54 +0800386 }
387 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600388 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 }
James Feist4cde5d92020-06-11 10:39:55 -0700390 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500391}
Jennifer Lee729dae72018-04-24 15:59:34 -0700392
Andrew Geissler0554c982019-04-23 14:40:12 -0500393/**
394 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
395 * SimpleUpdate action.
396 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700397inline void requestRoutesUpdateServiceActionsSimpleUpdate(App& app)
Andrew Geissler0554c982019-04-23 14:40:12 -0500398{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700399 BMCWEB_ROUTE(
400 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
Ed Tanoused398212021-06-09 17:05:54 -0700401 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 .methods(boost::beast::http::verb::post)(
403 [&app](const crow::Request& req,
404 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000405 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700406 {
407 return;
408 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700409
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 std::optional<std::string> transferProtocol;
411 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500412
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
Andrew Geissler0554c982019-04-23 14:40:12 -0500414
Ed Tanous002d39b2022-05-31 08:59:27 -0700415 // User can pass in both TransferProtocol and ImageURI parameters or
416 // they can pass in just the ImageURI with the transfer protocol
417 // embedded within it.
418 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
419 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
Andrew Geissler0554c982019-04-23 14:40:12 -0500420
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
422 transferProtocol, "ImageURI", imageURI))
423 {
424 BMCWEB_LOG_DEBUG
425 << "Missing TransferProtocol or ImageURI parameter";
426 return;
427 }
428 if (!transferProtocol)
429 {
430 // Must be option 2
431 // Verify ImageURI has transfer protocol in it
432 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500433 if ((separator == std::string::npos) ||
434 ((separator + 1) > imageURI.size()))
435 {
436 messages::actionParameterValueTypeError(
437 asyncResp->res, imageURI, "ImageURI",
438 "UpdateService.SimpleUpdate");
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
440 << imageURI;
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530441 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530442 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 transferProtocol = imageURI.substr(0, separator);
444 // Ensure protocol is upper case for a common comparison path
445 // below
446 boost::to_upper(*transferProtocol);
447 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
448 << *transferProtocol;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530449
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 // Adjust imageURI to not have the protocol on it for parsing
451 // below
452 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
453 imageURI = imageURI.substr(separator + 3);
454 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
455 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530456
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 // OpenBMC currently only supports TFTP
458 if (*transferProtocol != "TFTP")
459 {
460 messages::actionParameterNotSupported(asyncResp->res,
461 "TransferProtocol",
462 "UpdateService.SimpleUpdate");
463 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
464 << *transferProtocol;
465 return;
466 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700467
Ed Tanous002d39b2022-05-31 08:59:27 -0700468 // Format should be <IP or Hostname>/<file> for imageURI
469 size_t separator = imageURI.find('/');
470 if ((separator == std::string::npos) ||
471 ((separator + 1) > imageURI.size()))
472 {
473 messages::actionParameterValueTypeError(
474 asyncResp->res, imageURI, "ImageURI",
475 "UpdateService.SimpleUpdate");
476 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
477 return;
478 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700479
Ed Tanous002d39b2022-05-31 08:59:27 -0700480 std::string tftpServer = imageURI.substr(0, separator);
481 std::string fwFile = imageURI.substr(separator + 1);
482 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700483
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 // Setup callback for when new software detected
485 // Give TFTP 10 minutes to complete
486 monitorForSoftwareAvailable(
487 asyncResp, req,
488 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
489 600);
490
491 // TFTP can take up to 10 minutes depending on image size and
492 // connection speed. Return to caller as soon as the TFTP operation
493 // has been started. The callback above will ensure the activate
494 // is started once the download has completed
495 redfish::messages::success(asyncResp->res);
496
497 // Call TFTP service
498 crow::connections::systemBus->async_method_call(
499 [](const boost::system::error_code ec) {
500 if (ec)
501 {
502 // messages::internalError(asyncResp->res);
503 cleanUp();
504 BMCWEB_LOG_DEBUG << "error_code = " << ec;
505 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
506 }
507 else
508 {
509 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
510 }
511 },
512 "xyz.openbmc_project.Software.Download",
513 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
514 "DownloadViaTFTP", fwFile, tftpServer);
515
516 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700517 });
518}
519
Ed Tanousc2051d12022-05-11 12:21:55 -0700520inline void
521 handleUpdateServicePost(App& app, const crow::Request& req,
522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
523{
Carson Labrado3ba00072022-06-06 19:40:56 +0000524 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -0700525 {
526 return;
527 }
528 BMCWEB_LOG_DEBUG << "doPost...";
529
530 // Setup callback for when new software detected
531 monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
532
533 std::string filepath(
534 "/tmp/images/" +
535 boost::uuids::to_string(boost::uuids::random_generator()()));
536 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
537 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
538 std::ofstream::trunc);
539 out << req.body;
540 out.close();
541 BMCWEB_LOG_DEBUG << "file upload complete!!";
542}
543
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700544inline void requestRoutesUpdateService(App& app)
545{
546 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700547 .privileges(redfish::privileges::getUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700548 .methods(boost::beast::http::verb::get)(
549 [&app](const crow::Request& req,
550 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000551 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700552 {
553 return;
554 }
555 asyncResp->res.jsonValue["@odata.type"] =
556 "#UpdateService.v1_5_0.UpdateService";
557 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
558 asyncResp->res.jsonValue["Id"] = "UpdateService";
559 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
560 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700561
Ed Tanous32ca38a2022-05-11 12:36:59 -0700562#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
Ed Tanous002d39b2022-05-31 08:59:27 -0700563 // See note about later on in this file about why this is neccesary
564 // This is "Wrong" per the standard, but is done temporarily to
565 // avoid noise in failing tests as people transition to having this
566 // option disabled
567 asyncResp->res.addHeader(boost::beast::http::field::allow,
568 "GET, PATCH, HEAD");
Ed Tanous32ca38a2022-05-11 12:36:59 -0700569#endif
570
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 asyncResp->res.jsonValue["HttpPushUri"] =
572 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -0700573
Ed Tanous002d39b2022-05-31 08:59:27 -0700574 // UpdateService cannot be disabled
575 asyncResp->res.jsonValue["ServiceEnabled"] = true;
576 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
577 "/redfish/v1/UpdateService/FirmwareInventory";
578 // Get the MaxImageSizeBytes
579 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
580 bmcwebHttpReqBodyLimitMb * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +0530581
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700582#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
Ed Tanous002d39b2022-05-31 08:59:27 -0700583 // Update Actions object.
584 nlohmann::json& updateSvcSimpleUpdate =
585 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
586 updateSvcSimpleUpdate["target"] =
587 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
588 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
589 "TFTP"};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700590#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700591 // Get the current ApplyTime value
592 sdbusplus::asio::getProperty<std::string>(
593 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
594 "/xyz/openbmc_project/software/apply_time",
595 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
596 [asyncResp](const boost::system::error_code ec,
597 const std::string& applyTime) {
598 if (ec)
599 {
600 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
601 messages::internalError(asyncResp->res);
602 return;
603 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530604
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 // Store the ApplyTime Value
606 if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
607 "RequestedApplyTimes.Immediate")
608 {
609 asyncResp->res.jsonValue["HttpPushUriOptions"]
610 ["HttpPushUriApplyTime"]["ApplyTime"] =
611 "Immediate";
612 }
613 else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
614 "RequestedApplyTimes.OnReset")
615 {
616 asyncResp->res.jsonValue["HttpPushUriOptions"]
617 ["HttpPushUriApplyTime"]["ApplyTime"] =
618 "OnReset";
619 }
620 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 });
622 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700623 .privileges(redfish::privileges::patchUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 .methods(boost::beast::http::verb::patch)(
625 [&app](const crow::Request& req,
626 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000627 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700628 {
629 return;
630 }
631 BMCWEB_LOG_DEBUG << "doPatch...";
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530632
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 std::optional<nlohmann::json> pushUriOptions;
634 if (!json_util::readJsonPatch(req, asyncResp->res, "HttpPushUriOptions",
635 pushUriOptions))
636 {
637 return;
638 }
639
640 if (pushUriOptions)
641 {
642 std::optional<nlohmann::json> pushUriApplyTime;
643 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
644 "HttpPushUriApplyTime", pushUriApplyTime))
George Liu0fda0f12021-11-16 10:06:17 +0800645 {
646 return;
647 }
648
Ed Tanous002d39b2022-05-31 08:59:27 -0700649 if (pushUriApplyTime)
George Liu0fda0f12021-11-16 10:06:17 +0800650 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700651 std::optional<std::string> applyTime;
652 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
653 "ApplyTime", applyTime))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
Ed Tanousc711bf82018-07-30 16:31:33 -0700655 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 }
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700657
Ed Tanous002d39b2022-05-31 08:59:27 -0700658 if (applyTime)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700660 std::string applyTimeNewVal;
661 if (applyTime == "Immediate")
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700662 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700663 applyTimeNewVal =
664 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
665 }
666 else if (applyTime == "OnReset")
667 {
668 applyTimeNewVal =
669 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
670 }
671 else
672 {
673 BMCWEB_LOG_INFO
674 << "ApplyTime value is not in the list of acceptable values";
675 messages::propertyValueNotInList(
676 asyncResp->res, *applyTime, "ApplyTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700677 return;
678 }
679
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 // Set the requested image apply time value
681 crow::connections::systemBus->async_method_call(
682 [asyncResp](const boost::system::error_code ec) {
683 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700684 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
686 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700687 return;
688 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700689 messages::success(asyncResp->res);
690 },
691 "xyz.openbmc_project.Settings",
692 "/xyz/openbmc_project/software/apply_time",
693 "org.freedesktop.DBus.Properties", "Set",
694 "xyz.openbmc_project.Software.ApplyTime",
695 "RequestedApplyTime",
696 dbus::utility::DbusVariantType{applyTimeNewVal});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700697 }
George Liu0fda0f12021-11-16 10:06:17 +0800698 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 }
George Liu0fda0f12021-11-16 10:06:17 +0800700 });
Ed Tanousc2051d12022-05-11 12:21:55 -0700701
Ed Tanous4dc23f32022-05-11 11:32:19 -0700702// The "old" behavior of the update service URI causes redfish-service validator
703// failures when the Allow header is supported, given that in the spec,
704// UpdateService does not allow POST. in openbmc, we unfortunately reused that
705// resource as our HttpPushUri as well. A number of services, including the
706// openbmc tests, and documentation have hardcoded that erroneous API, instead
707// of relying on HttpPushUri as the spec requires. This option will exist
708// temporarily to allow the old behavior until Q4 2022, at which time it will be
709// removed.
710#ifdef BMCWEB_ENABLE_REDFISH_UPDATESERVICE_OLD_POST_URL
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700711 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
Ed Tanoused398212021-06-09 17:05:54 -0700712 .privileges(redfish::privileges::postUpdateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700713 .methods(boost::beast::http::verb::post)(
714 [&app](const crow::Request& req,
715 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
716 asyncResp->res.addHeader(
717 boost::beast::http::field::warning,
718 "299 - \"POST to /redfish/v1/UpdateService is deprecated. Use "
719 "the value contained within HttpPushUri.\"");
720 handleUpdateServicePost(app, req, asyncResp);
Ed Tanous4dc23f32022-05-11 11:32:19 -0700721 });
722#endif
723 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
724 .privileges(redfish::privileges::postUpdateService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700725 .methods(boost::beast::http::verb::post)(
Ed Tanousc2051d12022-05-11 12:21:55 -0700726 std::bind_front(handleUpdateServicePost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700727}
728
729inline void requestRoutesSoftwareInventoryCollection(App& app)
730{
731 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
Ed Tanoused398212021-06-09 17:05:54 -0700732 .privileges(redfish::privileges::getSoftwareInventoryCollection)
Ed Tanous14766872022-03-15 10:44:42 -0700733 .methods(boost::beast::http::verb::get)(
734 [&app](const crow::Request& req,
735 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000736 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700737 {
738 return;
739 }
740 asyncResp->res.jsonValue["@odata.type"] =
741 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
742 asyncResp->res.jsonValue["@odata.id"] =
743 "/redfish/v1/UpdateService/FirmwareInventory";
744 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
745
746 crow::connections::systemBus->async_method_call(
747 [asyncResp](
748 const boost::system::error_code ec,
749 const dbus::utility::MapperGetSubTreeResponse& subtree) {
750 if (ec)
751 {
752 messages::internalError(asyncResp->res);
753 return;
754 }
755 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
756 asyncResp->res.jsonValue["Members@odata.count"] = 0;
757
758 for (const auto& obj : subtree)
759 {
760 sdbusplus::message::object_path path(obj.first);
761 std::string swId = path.filename();
762 if (swId.empty())
Ed Tanous14766872022-03-15 10:44:42 -0700763 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700764 messages::internalError(asyncResp->res);
765 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
Ed Tanous14766872022-03-15 10:44:42 -0700766 return;
767 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700768
Ed Tanous002d39b2022-05-31 08:59:27 -0700769 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
770 nlohmann::json::object_t member;
771 member["@odata.id"] =
772 "/redfish/v1/UpdateService/FirmwareInventory/" + swId;
773 members.push_back(std::move(member));
774 asyncResp->res.jsonValue["Members@odata.count"] =
775 members.size();
776 }
777 },
778 // Note that only firmware levels associated with a device
779 // are stored under /xyz/openbmc_project/software therefore
780 // to ensure only real FirmwareInventory items are returned,
781 // this full object path must be used here as input to
782 // mapper
783 "xyz.openbmc_project.ObjectMapper",
784 "/xyz/openbmc_project/object_mapper",
785 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
786 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
787 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
788 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700789}
790/* Fill related item links (i.e. bmc, bios) in for inventory */
791inline static void
792 getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
793 const std::string& purpose)
794{
Willy Tueee00132022-06-14 14:53:17 -0700795 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700796 {
797 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700798 nlohmann::json::object_t item;
799 item["@odata.id"] = "/redfish/v1/Managers/bmc";
800 relatedItem.push_back(std::move(item));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700801 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
802 }
Willy Tueee00132022-06-14 14:53:17 -0700803 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700804 {
805 nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -0700806 nlohmann::json::object_t item;
807 item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
808 relatedItem.push_back(std::move(item));
Jiaqing Zhao1a6e51a2022-01-19 19:20:24 +0800809 aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700810 }
811 else
812 {
813 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
814 }
815}
816
Willy Tuaf246602022-06-14 15:51:53 -0700817inline void
818 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& service, const std::string& path,
820 const std::string& swId)
821{
822 crow::connections::systemBus->async_method_call(
823 [asyncResp,
824 swId](const boost::system::error_code errorCode,
825 const dbus::utility::DBusPropertiesMap& propertiesList) {
826 if (errorCode)
827 {
828 messages::internalError(asyncResp->res);
829 return;
830 }
831 const std::string* swInvPurpose = nullptr;
832 const std::string* version = nullptr;
833 for (const auto& property : propertiesList)
834 {
835 if (property.first == "Purpose")
836 {
837 swInvPurpose = std::get_if<std::string>(&property.second);
838 }
839 else if (property.first == "Version")
840 {
841 version = std::get_if<std::string>(&property.second);
842 }
843 }
844
845 if (swInvPurpose == nullptr)
846 {
847 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
848 messages::internalError(asyncResp->res);
849 return;
850 }
851
852 BMCWEB_LOG_DEBUG << "swInvPurpose = " << *swInvPurpose;
853
854 if (version == nullptr)
855 {
856 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
857
858 messages::internalError(asyncResp->res);
859
860 return;
861 }
862 asyncResp->res.jsonValue["Version"] = *version;
863 asyncResp->res.jsonValue["Id"] = swId;
864
865 // swInvPurpose is of format:
866 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
867 // Translate this to "ABC image"
868 size_t endDesc = swInvPurpose->rfind('.');
869 if (endDesc == std::string::npos)
870 {
871 messages::internalError(asyncResp->res);
872 return;
873 }
874 endDesc++;
875 if (endDesc >= swInvPurpose->size())
876 {
877 messages::internalError(asyncResp->res);
878 return;
879 }
880
881 std::string formatDesc = swInvPurpose->substr(endDesc);
882 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
883 getRelatedItems(asyncResp, *swInvPurpose);
884 },
885 service, path, "org.freedesktop.DBus.Properties", "GetAll",
886 "xyz.openbmc_project.Software.Version");
887}
888
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700889inline void requestRoutesSoftwareInventory(App& app)
890{
891 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700892 .privileges(redfish::privileges::getSoftwareInventory)
Ed Tanous002d39b2022-05-31 08:59:27 -0700893 .methods(boost::beast::http::verb::get)(
894 [&app](const crow::Request& req,
895 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
896 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000897 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700898 {
899 return;
900 }
901 std::shared_ptr<std::string> swId =
902 std::make_shared<std::string>(param);
903
904 asyncResp->res.jsonValue["@odata.id"] =
905 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
906
907 crow::connections::systemBus->async_method_call(
908 [asyncResp,
909 swId](const boost::system::error_code ec,
910 const dbus::utility::MapperGetSubTreeResponse& subtree) {
911 BMCWEB_LOG_DEBUG << "doGet callback...";
912 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700913 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700914 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700915 return;
916 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700917
Ed Tanous002d39b2022-05-31 08:59:27 -0700918 // Ensure we find our input swId, otherwise return an error
919 bool found = false;
920 for (const std::pair<std::string,
921 std::vector<std::pair<
922 std::string, std::vector<std::string>>>>&
923 obj : subtree)
924 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700925 if (!obj.first.ends_with(*swId))
Ed Tanous002d39b2022-05-31 08:59:27 -0700926 {
927 continue;
928 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700929
Ed Tanous002d39b2022-05-31 08:59:27 -0700930 if (obj.second.empty())
931 {
932 continue;
933 }
934
935 found = true;
Willy Tueee00132022-06-14 14:53:17 -0700936 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
Willy Tuaf246602022-06-14 15:51:53 -0700937 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
938 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700939 }
940 if (!found)
941 {
942 BMCWEB_LOG_ERROR << "Input swID " << *swId << " not found!";
943 messages::resourceMissingAtURI(
944 asyncResp->res, crow::utility::urlFromPieces(
945 "redfish", "v1", "UpdateService",
946 "FirmwareInventory", *swId));
947 return;
948 }
949 asyncResp->res.jsonValue["@odata.type"] =
950 "#SoftwareInventory.v1_1_0.SoftwareInventory";
951 asyncResp->res.jsonValue["Name"] = "Software Inventory";
952 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953
Ed Tanous002d39b2022-05-31 08:59:27 -0700954 asyncResp->res.jsonValue["Updateable"] = false;
Willy Tueee00132022-06-14 14:53:17 -0700955 sw_util::getSwUpdatableStatus(asyncResp, swId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700956 },
957 "xyz.openbmc_project.ObjectMapper",
958 "/xyz/openbmc_project/object_mapper",
959 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
960 static_cast<int32_t>(0),
961 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700962 });
963}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700964
965} // namespace redfish