blob: ca1234f3eca4b958999592d3710af2d051e482db [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
18#include "node.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070019
Jennifer Lee729dae72018-04-24 15:59:34 -070020#include <boost/container/flat_map.hpp>
Andrew Geissler87d84722019-02-28 14:28:39 -060021#include <utils/fw_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050022
Ed Tanousabf2add2019-01-22 16:40:12 -080023#include <variant>
Jennifer Lee729dae72018-04-24 15:59:34 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace redfish
26{
Ed Tanous27826b52018-10-29 11:40:58 -070027
Andrew Geissler0e7de462019-03-04 19:11:54 -060028// Match signals added on software path
Jennifer Leeacb7cfb2018-06-07 16:08:15 -070029static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
James Feist4cde5d92020-06-11 10:39:55 -070030static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060031// Only allow one update at a time
32static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050033// Timer for software available
Ed Tanous271584a2019-07-09 16:24:22 -070034static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050035
36static void cleanUp()
37{
38 fwUpdateInProgress = false;
39 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -070040 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -050041}
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042static void activateImage(const std::string& objPath,
43 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -050044{
45 BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
46 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +000047 [](const boost::system::error_code errorCode) {
48 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050049 {
Ed Tanous81ce6092020-12-17 16:54:55 +000050 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
51 BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
Andrew Geissler86adcd62019-04-18 10:58:05 -050052 }
53 },
54 service, objPath, "org.freedesktop.DBus.Properties", "Set",
55 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
56 std::variant<std::string>(
57 "xyz.openbmc_project.Software.Activation.RequestedActivations."
58 "Active"));
59}
Andrew Geissler0554c982019-04-23 14:40:12 -050060
61// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
62// then no asyncResp updates will occur
zhanghch058d1b46d2021-04-01 11:18:24 +080063static void
64 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
65 sdbusplus::message::message& m,
66 const crow::Request& req)
Andrew Geissler86adcd62019-04-18 10:58:05 -050067{
68 std::vector<std::pair<
69 std::string,
70 std::vector<std::pair<std::string, std::variant<std::string>>>>>
71 interfacesProperties;
72
73 sdbusplus::message::object_path objPath;
74
75 m.read(objPath, interfacesProperties);
76
77 BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050078 for (auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -050079 {
80 BMCWEB_LOG_DEBUG << "interface = " << interface.first;
81
82 if (interface.first == "xyz.openbmc_project.Software.Activation")
83 {
Andrew Geissler86adcd62019-04-18 10:58:05 -050084 // Retrieve service and activate
85 crow::connections::systemBus->async_method_call(
James Feistfe306722020-03-12 16:32:08 -070086 [objPath, asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +000087 req](const boost::system::error_code errorCode,
James Feistfe306722020-03-12 16:32:08 -070088 const std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -050089 std::string, std::vector<std::string>>>& objInfo) {
Ed Tanous81ce6092020-12-17 16:54:55 +000090 if (errorCode)
Andrew Geissler86adcd62019-04-18 10:58:05 -050091 {
Ed Tanous81ce6092020-12-17 16:54:55 +000092 BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
Andrew Geissler86adcd62019-04-18 10:58:05 -050093 BMCWEB_LOG_DEBUG << "error msg = "
Ed Tanous81ce6092020-12-17 16:54:55 +000094 << errorCode.message();
Andrew Geissler0554c982019-04-23 14:40:12 -050095 if (asyncResp)
96 {
97 messages::internalError(asyncResp->res);
98 }
Andrew Geissler86adcd62019-04-18 10:58:05 -050099 cleanUp();
100 return;
101 }
102 // Ensure we only got one service back
103 if (objInfo.size() != 1)
104 {
105 BMCWEB_LOG_ERROR << "Invalid Object Size "
106 << objInfo.size();
Andrew Geissler0554c982019-04-23 14:40:12 -0500107 if (asyncResp)
108 {
109 messages::internalError(asyncResp->res);
110 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500111 cleanUp();
112 return;
113 }
114 // cancel timer only when
115 // xyz.openbmc_project.Software.Activation interface
116 // is added
117 fwAvailableTimer = nullptr;
118
119 activateImage(objPath.str, objInfo[0].first);
Andrew Geissler0554c982019-04-23 14:40:12 -0500120 if (asyncResp)
121 {
James Feist32898ce2020-03-10 16:16:52 -0700122 std::shared_ptr<task::TaskData> task =
123 task::TaskData::createTask(
124 [](boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500125 sdbusplus::message::message& msg,
126 const std::shared_ptr<task::TaskData>&
127 taskData) {
James Feist32898ce2020-03-10 16:16:52 -0700128 if (ec)
129 {
130 return task::completed;
131 }
132
133 std::string iface;
134 boost::container::flat_map<
James Feistfd9ab9e2020-05-19 13:48:07 -0700135 std::string,
136 std::variant<std::string, uint8_t>>
James Feist32898ce2020-03-10 16:16:52 -0700137 values;
James Feist32898ce2020-03-10 16:16:52 -0700138
James Feiste5d50062020-05-11 17:29:00 -0700139 std::string index =
140 std::to_string(taskData->index);
James Feistfd9ab9e2020-05-19 13:48:07 -0700141 msg.read(iface, values);
James Feiste5d50062020-05-11 17:29:00 -0700142
James Feistfd9ab9e2020-05-19 13:48:07 -0700143 if (iface == "xyz.openbmc_project.Software."
144 "Activation")
James Feist32898ce2020-03-10 16:16:52 -0700145 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700146 auto findActivation =
147 values.find("Activation");
148 if (findActivation == values.end())
149 {
150 return !task::completed;
151 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500152 std::string* state =
James Feistfd9ab9e2020-05-19 13:48:07 -0700153 std::get_if<std::string>(
154 &(findActivation->second));
155
156 if (state == nullptr)
157 {
158 taskData->messages.emplace_back(
159 messages::internalError());
160 return task::completed;
161 }
162
163 if (boost::ends_with(*state,
164 "Invalid") ||
165 boost::ends_with(*state, "Failed"))
166 {
167 taskData->state = "Exception";
168 taskData->status = "Warning";
169 taskData->messages.emplace_back(
170 messages::taskAborted(index));
171 return task::completed;
172 }
173
174 if (boost::ends_with(*state, "Staged"))
175 {
176 taskData->state = "Stopping";
177 taskData->messages.emplace_back(
178 messages::taskPaused(index));
179
180 // its staged, set a long timer to
181 // allow them time to complete the
182 // update (probably cycle the
183 // system) if this expires then
184 // task will be cancelled
185 taskData->extendTimer(
186 std::chrono::hours(5));
187 return !task::completed;
188 }
189
190 if (boost::ends_with(*state, "Active"))
191 {
192 taskData->messages.emplace_back(
193 messages::taskCompletedOK(
194 index));
195 taskData->state = "Completed";
196 return task::completed;
197 }
James Feist32898ce2020-03-10 16:16:52 -0700198 }
James Feistfd9ab9e2020-05-19 13:48:07 -0700199 else if (iface ==
200 "xyz.openbmc_project.Software."
201 "ActivationProgress")
James Feist32898ce2020-03-10 16:16:52 -0700202 {
James Feistfd9ab9e2020-05-19 13:48:07 -0700203 auto findProgress =
204 values.find("Progress");
205 if (findProgress == values.end())
206 {
207 return !task::completed;
208 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500209 uint8_t* progress =
James Feistfd9ab9e2020-05-19 13:48:07 -0700210 std::get_if<uint8_t>(
211 &(findProgress->second));
James Feist32898ce2020-03-10 16:16:52 -0700212
James Feistfd9ab9e2020-05-19 13:48:07 -0700213 if (progress == nullptr)
214 {
215 taskData->messages.emplace_back(
216 messages::internalError());
217 return task::completed;
218 }
George Liu6868ff52021-01-02 11:37:41 +0800219 taskData->percentComplete =
220 static_cast<int>(*progress);
James Feist32898ce2020-03-10 16:16:52 -0700221 taskData->messages.emplace_back(
James Feistfd9ab9e2020-05-19 13:48:07 -0700222 messages::taskProgressChanged(
223 index, static_cast<size_t>(
224 *progress)));
225
226 // if we're getting status updates it's
227 // still alive, update timer
228 taskData->extendTimer(
229 std::chrono::minutes(5));
James Feist32898ce2020-03-10 16:16:52 -0700230 }
231
232 // as firmware update often results in a
233 // reboot, the task may never "complete"
234 // unless it is an error
235
236 return !task::completed;
237 },
238 "type='signal',interface='org.freedesktop.DBus."
239 "Properties',"
James Feistfd9ab9e2020-05-19 13:48:07 -0700240 "member='PropertiesChanged',path='" +
James Feist32898ce2020-03-10 16:16:52 -0700241 objPath.str + "'");
242 task->startTimer(std::chrono::minutes(5));
243 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -0700244 task->payload.emplace(req);
Andrew Geissler0554c982019-04-23 14:40:12 -0500245 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500246 fwUpdateInProgress = false;
247 },
248 "xyz.openbmc_project.ObjectMapper",
249 "/xyz/openbmc_project/object_mapper",
250 "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 std::array<const char*, 1>{
Andrew Geissler86adcd62019-04-18 10:58:05 -0500252 "xyz.openbmc_project.Software.Activation"});
253 }
254 }
255}
256
Andrew Geissler0554c982019-04-23 14:40:12 -0500257// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
258// then no asyncResp updates will occur
Ed Tanousb5a76932020-09-29 16:16:58 -0700259static void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800260 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
261 const crow::Request& req, const std::string& url,
262 int timeoutTimeSeconds = 10)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263{
264 // Only allow one FW update at a time
265 if (fwUpdateInProgress != false)
266 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500267 if (asyncResp)
268 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500269 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
270 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500271 return;
272 }
273
Andrew Geissler0554c982019-04-23 14:40:12 -0500274 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700275 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276
Ed Tanous271584a2019-07-09 16:24:22 -0700277 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500278
279 fwAvailableTimer->async_wait(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280 [asyncResp](const boost::system::error_code& ec) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500281 cleanUp();
282 if (ec == boost::asio::error::operation_aborted)
283 {
284 // expected, we were canceled before the timer completed.
285 return;
286 }
287 BMCWEB_LOG_ERROR
288 << "Timed out waiting for firmware object being created";
289 BMCWEB_LOG_ERROR
290 << "FW image may has already been uploaded to server";
291 if (ec)
292 {
293 BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
294 return;
295 }
Andrew Geissler0554c982019-04-23 14:40:12 -0500296 if (asyncResp)
297 {
298 redfish::messages::internalError(asyncResp->res);
299 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500300 });
301
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500302 auto callback = [asyncResp, req](sdbusplus::message::message& m) {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500303 BMCWEB_LOG_DEBUG << "Match fired";
James Feistfe306722020-03-12 16:32:08 -0700304 softwareInterfaceAdded(asyncResp, m, req);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500305 };
306
307 fwUpdateInProgress = true;
308
309 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
310 *crow::connections::systemBus,
311 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
312 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
313 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700314
315 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match::match>(
316 *crow::connections::systemBus,
317 "type='signal',member='PropertiesChanged',path_namespace='/xyz/"
318 "openbmc_project/logging/entry',"
319 "arg0='xyz.openbmc_project.Logging.Entry'",
320 [asyncResp, url](sdbusplus::message::message& m) {
321 BMCWEB_LOG_DEBUG << "Error Match fired";
322 boost::container::flat_map<std::string, std::variant<std::string>>
323 values;
324 std::string objName;
325 m.read(objName, values);
326 auto find = values.find("Message");
327 if (find == values.end())
328 {
329 return;
330 }
331 std::string* type = std::get_if<std::string>(&(find->second));
332 if (type == nullptr)
333 {
334 return; // if this was our message, timeout will cover it
335 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600336 if (!boost::starts_with(*type, "xyz.openbmc_project.Software"))
James Feist4cde5d92020-06-11 10:39:55 -0700337 {
338 return;
339 }
340 if (*type ==
341 "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
342 {
343 redfish::messages::invalidUpload(asyncResp->res, url,
344 "Invalid archive");
345 }
346 else if (*type == "xyz.openbmc_project.Software.Image.Error."
347 "ManifestFileFailure")
348 {
349 redfish::messages::invalidUpload(asyncResp->res, url,
350 "Invalid manifest");
351 }
352 else if (*type ==
353 "xyz.openbmc_project.Software.Image.Error.ImageFailure")
354 {
355 redfish::messages::invalidUpload(asyncResp->res, url,
356 "Invalid image format");
357 }
Gunnar Mills88b3dd12020-11-20 14:26:04 -0600358 else if (*type == "xyz.openbmc_project.Software.Version.Error."
359 "AlreadyExists")
360 {
361
362 redfish::messages::invalidUpload(
363 asyncResp->res, url, "Image version already exists");
364
365 redfish::messages::resourceAlreadyExists(
366 asyncResp->res, "UpdateService.v1_4_0.UpdateService",
367 "Version", "uploaded version");
368 }
James Feist4cde5d92020-06-11 10:39:55 -0700369 else if (*type ==
370 "xyz.openbmc_project.Software.Image.Error.BusyFailure")
371 {
372 redfish::messages::resourceExhaustion(asyncResp->res, url);
373 }
374 else
375 {
376 redfish::messages::internalError(asyncResp->res);
377 }
378 fwAvailableTimer = nullptr;
379 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500380}
Jennifer Lee729dae72018-04-24 15:59:34 -0700381
Andrew Geissler0554c982019-04-23 14:40:12 -0500382/**
383 * UpdateServiceActionsSimpleUpdate class supports handle POST method for
384 * SimpleUpdate action.
385 */
386class UpdateServiceActionsSimpleUpdate : public Node
387{
388 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700389 UpdateServiceActionsSimpleUpdate(App& app) :
Andrew Geissler0554c982019-04-23 14:40:12 -0500390 Node(app,
391 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
392 {
393 entityPrivileges = {
394 {boost::beast::http::verb::get, {{"Login"}}},
395 {boost::beast::http::verb::head, {{"Login"}}},
396 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
397 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
398 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
399 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
400 }
401
402 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800403 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
404 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000405 const std::vector<std::string>&) override
Andrew Geissler0554c982019-04-23 14:40:12 -0500406 {
407 std::optional<std::string> transferProtocol;
408 std::string imageURI;
Andrew Geissler0554c982019-04-23 14:40:12 -0500409
410 BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost";
411
412 // User can pass in both TransferProtocol and ImageURI parameters or
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500413 // they can pass in just the ImageURI with the transfer protocol
414 // embedded within it.
Andrew Geissler0554c982019-04-23 14:40:12 -0500415 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
416 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
417
418 if (!json_util::readJson(req, asyncResp->res, "TransferProtocol",
419 transferProtocol, "ImageURI", imageURI))
420 {
421 BMCWEB_LOG_DEBUG
422 << "Missing TransferProtocol or ImageURI parameter";
423 return;
424 }
425 if (!transferProtocol)
426 {
427 // Must be option 2
428 // Verify ImageURI has transfer protocol in it
Ed Tanousf23b7292020-10-15 09:41:17 -0700429 size_t separator = imageURI.find(':');
Andrew Geissler0554c982019-04-23 14:40:12 -0500430 if ((separator == std::string::npos) ||
431 ((separator + 1) > imageURI.size()))
432 {
433 messages::actionParameterValueTypeError(
434 asyncResp->res, imageURI, "ImageURI",
435 "UpdateService.SimpleUpdate");
436 BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: "
437 << imageURI;
438 return;
439 }
440 transferProtocol = imageURI.substr(0, separator);
441 // Ensure protocol is upper case for a common comparison path below
442 boost::to_upper(*transferProtocol);
443 BMCWEB_LOG_DEBUG << "Encoded transfer protocol "
444 << *transferProtocol;
445
446 // Adjust imageURI to not have the protocol on it for parsing
447 // below
448 // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin
449 imageURI = imageURI.substr(separator + 3);
450 BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI;
451 }
452
453 // OpenBMC currently only supports TFTP
454 if (*transferProtocol != "TFTP")
455 {
456 messages::actionParameterNotSupported(asyncResp->res,
457 "TransferProtocol",
458 "UpdateService.SimpleUpdate");
459 BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: "
460 << *transferProtocol;
461 return;
462 }
463
464 // Format should be <IP or Hostname>/<file> for imageURI
Ed Tanousf23b7292020-10-15 09:41:17 -0700465 size_t separator = imageURI.find('/');
Andrew Geissler0554c982019-04-23 14:40:12 -0500466 if ((separator == std::string::npos) ||
467 ((separator + 1) > imageURI.size()))
468 {
469 messages::actionParameterValueTypeError(
470 asyncResp->res, imageURI, "ImageURI",
471 "UpdateService.SimpleUpdate");
472 BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI;
473 return;
474 }
475
476 std::string tftpServer = imageURI.substr(0, separator);
477 std::string fwFile = imageURI.substr(separator + 1);
478 BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
479
480 // Setup callback for when new software detected
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500481 // Give TFTP 10 minutes to complete
James Feist4cde5d92020-06-11 10:39:55 -0700482 monitorForSoftwareAvailable(
Albert Zhangd7a596b2021-01-20 16:39:12 +0800483 asyncResp, req,
James Feist4cde5d92020-06-11 10:39:55 -0700484 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500485 600);
Andrew Geissler0554c982019-04-23 14:40:12 -0500486
Gunnar Mills2618d5e2020-08-18 13:04:27 -0500487 // TFTP can take up to 10 minutes depending on image size and
Andrew Geissler0554c982019-04-23 14:40:12 -0500488 // connection speed. Return to caller as soon as the TFTP operation
489 // has been started. The callback above will ensure the activate
490 // is started once the download has completed
491 redfish::messages::success(asyncResp->res);
492
493 // Call TFTP service
494 crow::connections::systemBus->async_method_call(
495 [](const boost::system::error_code ec) {
496 if (ec)
497 {
498 // messages::internalError(asyncResp->res);
499 cleanUp();
500 BMCWEB_LOG_DEBUG << "error_code = " << ec;
501 BMCWEB_LOG_DEBUG << "error msg = " << ec.message();
502 }
503 else
504 {
505 BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success";
506 }
507 },
508 "xyz.openbmc_project.Software.Download",
509 "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
510 "DownloadViaTFTP", fwFile, tftpServer);
511
512 BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost";
513 }
514};
515
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516class UpdateService : public Node
517{
518 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700519 UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521 entityPrivileges = {
522 {boost::beast::http::verb::get, {{"Login"}}},
523 {boost::beast::http::verb::head, {{"Login"}}},
524 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
525 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
526 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
527 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700528 }
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700529
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800531 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
532 const crow::Request&, const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800534 asyncResp->res.jsonValue["@odata.type"] =
535 "#UpdateService.v1_4_0.UpdateService";
536 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
537 asyncResp->res.jsonValue["Id"] = "UpdateService";
538 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
539 asyncResp->res.jsonValue["Name"] = "Update Service";
540 asyncResp->res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
Ed Tanous0f74e642018-11-12 15:17:05 -0800541 // UpdateService cannot be disabled
zhanghch058d1b46d2021-04-01 11:18:24 +0800542 asyncResp->res.jsonValue["ServiceEnabled"] = true;
543 asyncResp->res.jsonValue["FirmwareInventory"] = {
Ed Tanous0f74e642018-11-12 15:17:05 -0800544 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
Andrew Geissler0554c982019-04-23 14:40:12 -0500545#ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE
546 // Update Actions object.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500547 nlohmann::json& updateSvcSimpleUpdate =
zhanghch058d1b46d2021-04-01 11:18:24 +0800548 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
Andrew Geissler0554c982019-04-23 14:40:12 -0500549 updateSvcSimpleUpdate["target"] =
550 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
551 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = {
552 "TFTP"};
553#endif
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530554 // Get the current ApplyTime value
555 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +0800556 [asyncResp](const boost::system::error_code ec,
557 const std::variant<std::string>& applyTime) {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530558 if (ec)
559 {
560 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +0800561 messages::internalError(asyncResp->res);
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530562 return;
563 }
564
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500565 const std::string* s = std::get_if<std::string>(&applyTime);
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530566 if (s == nullptr)
567 {
568 return;
569 }
570 // Store the ApplyTime Value
571 if (*s == "xyz.openbmc_project.Software.ApplyTime."
572 "RequestedApplyTimes.Immediate")
573 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800574 asyncResp->res
575 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]
576 ["ApplyTime"] = "Immediate";
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530577 }
578 else if (*s == "xyz.openbmc_project.Software.ApplyTime."
579 "RequestedApplyTimes.OnReset")
580 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800581 asyncResp->res
582 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]
583 ["ApplyTime"] = "OnReset";
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530584 }
585 },
586 "xyz.openbmc_project.Settings",
587 "/xyz/openbmc_project/software/apply_time",
588 "org.freedesktop.DBus.Properties", "Get",
589 "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 }
Andrew Geissler0e7de462019-03-04 19:11:54 -0600591
zhanghch058d1b46d2021-04-01 11:18:24 +0800592 void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
593 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000594 const std::vector<std::string>&) override
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530595 {
596 BMCWEB_LOG_DEBUG << "doPatch...";
597
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530598 std::optional<nlohmann::json> pushUriOptions;
zhanghch058d1b46d2021-04-01 11:18:24 +0800599 if (!json_util::readJson(req, asyncResp->res, "HttpPushUriOptions",
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530600 pushUriOptions))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530601 {
602 return;
603 }
604
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530605 if (pushUriOptions)
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530606 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530607 std::optional<nlohmann::json> pushUriApplyTime;
zhanghch058d1b46d2021-04-01 11:18:24 +0800608 if (!json_util::readJson(*pushUriOptions, asyncResp->res,
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530609 "HttpPushUriApplyTime", pushUriApplyTime))
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530610 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530611 return;
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530612 }
613
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530614 if (pushUriApplyTime)
615 {
616 std::optional<std::string> applyTime;
zhanghch058d1b46d2021-04-01 11:18:24 +0800617 if (!json_util::readJson(*pushUriApplyTime, asyncResp->res,
618 "ApplyTime", applyTime))
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530619 {
620 return;
621 }
622
623 if (applyTime)
624 {
625 std::string applyTimeNewVal;
626 if (applyTime == "Immediate")
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530627 {
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530628 applyTimeNewVal =
629 "xyz.openbmc_project.Software.ApplyTime."
630 "RequestedApplyTimes.Immediate";
631 }
632 else if (applyTime == "OnReset")
633 {
634 applyTimeNewVal =
635 "xyz.openbmc_project.Software.ApplyTime."
636 "RequestedApplyTimes.OnReset";
637 }
638 else
639 {
640 BMCWEB_LOG_INFO
641 << "ApplyTime value is not in the list of "
642 "acceptable values";
643 messages::propertyValueNotInList(
644 asyncResp->res, *applyTime, "ApplyTime");
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530645 return;
646 }
Jayashankar Padath274dfe62019-08-23 12:30:57 +0530647
648 // Set the requested image apply time value
649 crow::connections::systemBus->async_method_call(
650 [asyncResp](const boost::system::error_code ec) {
651 if (ec)
652 {
653 BMCWEB_LOG_ERROR << "D-Bus responses error: "
654 << ec;
655 messages::internalError(asyncResp->res);
656 return;
657 }
658 messages::success(asyncResp->res);
659 },
660 "xyz.openbmc_project.Settings",
661 "/xyz/openbmc_project/software/apply_time",
662 "org.freedesktop.DBus.Properties", "Set",
663 "xyz.openbmc_project.Software.ApplyTime",
664 "RequestedApplyTime",
665 std::variant<std::string>{applyTimeNewVal});
666 }
667 }
Jayashankar Padathfa1a5a32019-05-28 23:54:37 +0530668 }
669 }
670
zhanghch058d1b46d2021-04-01 11:18:24 +0800671 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
672 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +0000673 const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 {
675 BMCWEB_LOG_DEBUG << "doPost...";
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700676
Andrew Geissler86adcd62019-04-18 10:58:05 -0500677 // Setup callback for when new software detected
James Feist4cde5d92020-06-11 10:39:55 -0700678 monitorForSoftwareAvailable(asyncResp, req,
679 "/redfish/v1/UpdateService");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680
681 std::string filepath(
682 "/tmp/images/" +
683 boost::uuids::to_string(boost::uuids::random_generator()()));
684 BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
685 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
686 std::ofstream::trunc);
687 out << req.body;
688 out.close();
689 BMCWEB_LOG_DEBUG << "file upload complete!!";
690 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700691};
Ed Tanousc711bf82018-07-30 16:31:33 -0700692
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693class SoftwareInventoryCollection : public Node
694{
695 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700696 SoftwareInventoryCollection(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
698 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 entityPrivileges = {
700 {boost::beast::http::verb::get, {{"Login"}}},
701 {boost::beast::http::verb::head, {{"Login"}}},
702 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
703 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
704 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
705 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Jennifer Lee729dae72018-04-24 15:59:34 -0700706 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700707
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800709 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
710 const crow::Request&, const std::vector<std::string>&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800712 asyncResp->res.jsonValue["@odata.type"] =
Ed Tanous0f74e642018-11-12 15:17:05 -0800713 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +0800714 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous0f74e642018-11-12 15:17:05 -0800715 "/redfish/v1/UpdateService/FirmwareInventory";
zhanghch058d1b46d2021-04-01 11:18:24 +0800716 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
Ed Tanousc711bf82018-07-30 16:31:33 -0700717
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 crow::connections::systemBus->async_method_call(
719 [asyncResp](
720 const boost::system::error_code ec,
721 const std::vector<std::pair<
722 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500723 std::string, std::vector<std::string>>>>>&
724 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 if (ec)
726 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700727 messages::internalError(asyncResp->res);
Ed Tanousc711bf82018-07-30 16:31:33 -0700728 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 }
730 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
731 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jennifer Lee6c4eb9d2018-05-22 10:58:31 -0700732
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500733 for (auto& obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000735 sdbusplus::message::object_path path(obj.first);
736 std::string swId = path.filename();
737 if (swId.empty())
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700738 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700739 messages::internalError(asyncResp->res);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700740 BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
741 return;
742 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700743
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500744 nlohmann::json& members =
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500745 asyncResp->res.jsonValue["Members"];
746 members.push_back(
747 {{"@odata.id", "/redfish/v1/UpdateService/"
748 "FirmwareInventory/" +
749 swId}});
750 asyncResp->res.jsonValue["Members@odata.count"] =
751 members.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 }
753 },
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600754 // Note that only firmware levels associated with a device are
755 // stored under /xyz/openbmc_project/software therefore to ensure
756 // only real FirmwareInventory items are returned, this full object
757 // path must be used here as input to mapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 "xyz.openbmc_project.ObjectMapper",
759 "/xyz/openbmc_project/object_mapper",
Andrew Geissler2830a9c2020-01-06 10:18:11 -0600760 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
761 "/xyz/openbmc_project/software", static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500762 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 }
Jennifer Lee729dae72018-04-24 15:59:34 -0700764};
765
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766class SoftwareInventory : public Node
767{
768 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700769 SoftwareInventory(App& app) :
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
771 std::string())
772 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 entityPrivileges = {
774 {boost::beast::http::verb::get, {{"Login"}}},
775 {boost::beast::http::verb::head, {{"Login"}}},
776 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
777 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
778 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
779 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
780 }
781
782 private:
Andrew Geissler87d84722019-02-28 14:28:39 -0600783 /* Fill related item links (i.e. bmc, bios) in for inventory */
zhanghch058d1b46d2021-04-01 11:18:24 +0800784 static void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500785 const std::string& purpose)
Andrew Geissler87d84722019-02-28 14:28:39 -0600786 {
787 if (purpose == fw_util::bmcPurpose)
788 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500789 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Andrew Geissler87d84722019-02-28 14:28:39 -0600790 members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}});
791 aResp->res.jsonValue["Members@odata.count"] = members.size();
792 }
793 else if (purpose == fw_util::biosPurpose)
794 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500795 nlohmann::json& members = aResp->res.jsonValue["RelatedItem"];
Gunnar Millsf723d732020-02-26 11:20:49 -0600796 members.push_back(
797 {{"@odata.id", "/redfish/v1/Systems/system/Bios"}});
798 aResp->res.jsonValue["Members@odata.count"] = members.size();
Andrew Geissler87d84722019-02-28 14:28:39 -0600799 }
800 else
801 {
802 BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose;
803 }
804 }
805
zhanghch058d1b46d2021-04-01 11:18:24 +0800806 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
807 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500808 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 if (params.size() != 1)
811 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800812 messages::internalError(asyncResp->res);
813
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 return;
815 }
816
Ed Tanous3ae837c2018-08-07 14:41:19 -0700817 std::shared_ptr<std::string> swId =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 std::make_shared<std::string>(params[0]);
819
zhanghch058d1b46d2021-04-01 11:18:24 +0800820 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous3ae837c2018-08-07 14:41:19 -0700821 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822
823 crow::connections::systemBus->async_method_call(
Ed Tanous3ae837c2018-08-07 14:41:19 -0700824 [asyncResp, swId](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 const boost::system::error_code ec,
826 const std::vector<std::pair<
827 std::string, std::vector<std::pair<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500828 std::string, std::vector<std::string>>>>>&
829 subtree) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 BMCWEB_LOG_DEBUG << "doGet callback...";
831 if (ec)
832 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700833 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 return;
835 }
836
Andrew Geissler69132282019-07-01 11:00:35 -0500837 // Ensure we find our input swId, otherwise return an error
838 bool found = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 for (const std::pair<
840 std::string,
841 std::vector<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500842 std::pair<std::string, std::vector<std::string>>>>&
843 obj : subtree)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 {
Ed Tanous3ae837c2018-08-07 14:41:19 -0700845 if (boost::ends_with(obj.first, *swId) != true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
847 continue;
848 }
849
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700850 if (obj.second.size() < 1)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
852 continue;
853 }
854
Andrew Geissler69132282019-07-01 11:00:35 -0500855 found = true;
Andrew Geisslere0dd8052019-06-18 16:05:10 -0500856 fw_util::getFwStatus(asyncResp, swId, obj.second[0].first);
857
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 crow::connections::systemBus->async_method_call(
859 [asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +0000860 swId](const boost::system::error_code errorCode,
Ed Tanous3ae837c2018-08-07 14:41:19 -0700861 const boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500862 std::string, VariantType>& propertiesList) {
Ed Tanous81ce6092020-12-17 16:54:55 +0000863 if (errorCode)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700864 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700865 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 return;
867 }
868 boost::container::flat_map<
869 std::string, VariantType>::const_iterator it =
870 propertiesList.find("Purpose");
871 if (it == propertiesList.end())
872 {
873 BMCWEB_LOG_DEBUG
874 << "Can't find property \"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700875 messages::propertyMissing(asyncResp->res,
876 "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 return;
878 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500879 const std::string* swInvPurpose =
Ed Tanousabf2add2019-01-22 16:40:12 -0800880 std::get_if<std::string>(&it->second);
Ed Tanous3ae837c2018-08-07 14:41:19 -0700881 if (swInvPurpose == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 {
883 BMCWEB_LOG_DEBUG
884 << "wrong types for property\"Purpose\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700885 messages::propertyValueTypeError(asyncResp->res,
886 "", "Purpose");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 return;
888 }
889
Ed Tanous3ae837c2018-08-07 14:41:19 -0700890 BMCWEB_LOG_DEBUG << "swInvPurpose = "
891 << *swInvPurpose;
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700892 it = propertiesList.find("Version");
893 if (it == propertiesList.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894 {
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700895 BMCWEB_LOG_DEBUG
896 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700897 messages::propertyMissing(asyncResp->res,
898 "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700899 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 }
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700901
902 BMCWEB_LOG_DEBUG << "Version found!";
903
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500904 const std::string* version =
Ed Tanousabf2add2019-01-22 16:40:12 -0800905 std::get_if<std::string>(&it->second);
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700906
907 if (version == nullptr)
908 {
909 BMCWEB_LOG_DEBUG
910 << "Can't find property \"Version\"!";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700911
912 messages::propertyValueTypeError(asyncResp->res,
913 "", "Version");
Jennifer Leef4b65ab2018-09-18 12:00:13 -0700914 return;
915 }
916 asyncResp->res.jsonValue["Version"] = *version;
917 asyncResp->res.jsonValue["Id"] = *swId;
Andrew Geissler54daabe2019-02-13 13:54:15 -0600918
919 // swInvPurpose is of format:
920 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
James Feiste2e96772019-10-03 10:51:43 -0700921 // Translate this to "ABC image"
Ed Tanousf23b7292020-10-15 09:41:17 -0700922 size_t endDesc = swInvPurpose->rfind('.');
Andrew Geissler54daabe2019-02-13 13:54:15 -0600923 if (endDesc == std::string::npos)
924 {
925 messages::internalError(asyncResp->res);
926 return;
927 }
928 endDesc++;
929 if (endDesc >= swInvPurpose->size())
930 {
931 messages::internalError(asyncResp->res);
932 return;
933 }
934
935 std::string formatDesc =
936 swInvPurpose->substr(endDesc);
937 asyncResp->res.jsonValue["Description"] =
James Feiste2e96772019-10-03 10:51:43 -0700938 formatDesc + " image";
Andrew Geissler87d84722019-02-28 14:28:39 -0600939 getRelatedItems(asyncResp, *swInvPurpose);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 },
941 obj.second[0].first, obj.first,
942 "org.freedesktop.DBus.Properties", "GetAll",
943 "xyz.openbmc_project.Software.Version");
944 }
Andrew Geissler69132282019-07-01 11:00:35 -0500945 if (!found)
946 {
947 BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!";
948 messages::resourceMissingAtURI(
949 asyncResp->res,
950 "/redfish/v1/UpdateService/FirmwareInventory/" + *swId);
951 return;
952 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530953 asyncResp->res.jsonValue["@odata.type"] =
954 "#SoftwareInventory.v1_1_0.SoftwareInventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530955 asyncResp->res.jsonValue["Name"] = "Software Inventory";
Ayushi Smriti4e68c452019-09-04 14:37:55 +0530956 asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
AppaRao Puli3f8a7432020-01-29 02:36:32 +0530957
958 asyncResp->res.jsonValue["Updateable"] = false;
959 fw_util::getFwUpdateableStatus(asyncResp, swId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700960 },
961 "xyz.openbmc_project.ObjectMapper",
962 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700963 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
964 static_cast<int32_t>(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500965 std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700966 }
967};
968
969} // namespace redfish