1729dae72SJennifer Lee /* 2729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation 3729dae72SJennifer Lee // 4729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License"); 5729dae72SJennifer Lee // you may not use this file except in compliance with the License. 6729dae72SJennifer Lee // You may obtain a copy of the License at 7729dae72SJennifer Lee // 8729dae72SJennifer Lee // http://www.apache.org/licenses/LICENSE-2.0 9729dae72SJennifer Lee // 10729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software 11729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS, 12729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13729dae72SJennifer Lee // See the License for the specific language governing permissions and 14729dae72SJennifer Lee // limitations under the License. 15729dae72SJennifer Lee */ 16729dae72SJennifer Lee #pragma once 17729dae72SJennifer Lee 18729dae72SJennifer Lee #include "node.hpp" 191abe55efSEd Tanous 20729dae72SJennifer Lee #include <boost/container/flat_map.hpp> 2187d84729SAndrew Geissler #include <utils/fw_utils.hpp> 22abf2add6SEd Tanous #include <variant> 23729dae72SJennifer Lee 241abe55efSEd Tanous namespace redfish 251abe55efSEd Tanous { 2627826b5fSEd Tanous 270e7de46fSAndrew Geissler // Match signals added on software path 28acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; 290e7de46fSAndrew Geissler // Only allow one update at a time 300e7de46fSAndrew Geissler static bool fwUpdateInProgress = false; 3186adcd6dSAndrew Geissler // Timer for software available 32271584abSEd Tanous static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer; 3386adcd6dSAndrew Geissler 3486adcd6dSAndrew Geissler static void cleanUp() 3586adcd6dSAndrew Geissler { 3686adcd6dSAndrew Geissler fwUpdateInProgress = false; 3786adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 3886adcd6dSAndrew Geissler } 3986adcd6dSAndrew Geissler static void activateImage(const std::string &objPath, 4086adcd6dSAndrew Geissler const std::string &service) 4186adcd6dSAndrew Geissler { 4286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; 4386adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 4486adcd6dSAndrew Geissler [](const boost::system::error_code error_code) { 4586adcd6dSAndrew Geissler if (error_code) 4686adcd6dSAndrew Geissler { 4786adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 4886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); 4986adcd6dSAndrew Geissler } 5086adcd6dSAndrew Geissler }, 5186adcd6dSAndrew Geissler service, objPath, "org.freedesktop.DBus.Properties", "Set", 5286adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation", "RequestedActivation", 5386adcd6dSAndrew Geissler std::variant<std::string>( 5486adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation.RequestedActivations." 5586adcd6dSAndrew Geissler "Active")); 5686adcd6dSAndrew Geissler } 570554c984SAndrew Geissler 580554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 590554c984SAndrew Geissler // then no asyncResp updates will occur 6086adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 61fe306728SJames Feist sdbusplus::message::message &m, 62fe306728SJames Feist const crow::Request &req) 6386adcd6dSAndrew Geissler { 6486adcd6dSAndrew Geissler std::vector<std::pair< 6586adcd6dSAndrew Geissler std::string, 6686adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6786adcd6dSAndrew Geissler interfacesProperties; 6886adcd6dSAndrew Geissler 6986adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 7086adcd6dSAndrew Geissler 7186adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 7286adcd6dSAndrew Geissler 7386adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7486adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 7586adcd6dSAndrew Geissler { 7686adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7786adcd6dSAndrew Geissler 7886adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 7986adcd6dSAndrew Geissler { 8086adcd6dSAndrew Geissler // Found our interface, disable callbacks 8186adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 8286adcd6dSAndrew Geissler 8386adcd6dSAndrew Geissler // Retrieve service and activate 8486adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 85fe306728SJames Feist [objPath, asyncResp, 86fe306728SJames Feist req](const boost::system::error_code error_code, 8786adcd6dSAndrew Geissler const std::vector<std::pair< 8886adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 8986adcd6dSAndrew Geissler if (error_code) 9086adcd6dSAndrew Geissler { 9186adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 9286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 9386adcd6dSAndrew Geissler << error_code.message(); 940554c984SAndrew Geissler if (asyncResp) 950554c984SAndrew Geissler { 9686adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 970554c984SAndrew Geissler } 9886adcd6dSAndrew Geissler cleanUp(); 9986adcd6dSAndrew Geissler return; 10086adcd6dSAndrew Geissler } 10186adcd6dSAndrew Geissler // Ensure we only got one service back 10286adcd6dSAndrew Geissler if (objInfo.size() != 1) 10386adcd6dSAndrew Geissler { 10486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 10586adcd6dSAndrew Geissler << objInfo.size(); 1060554c984SAndrew Geissler if (asyncResp) 1070554c984SAndrew Geissler { 10886adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 1090554c984SAndrew Geissler } 11086adcd6dSAndrew Geissler cleanUp(); 11186adcd6dSAndrew Geissler return; 11286adcd6dSAndrew Geissler } 11386adcd6dSAndrew Geissler // cancel timer only when 11486adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 11586adcd6dSAndrew Geissler // is added 11686adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 11786adcd6dSAndrew Geissler 11886adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 1190554c984SAndrew Geissler if (asyncResp) 1200554c984SAndrew Geissler { 12132898ceaSJames Feist std::shared_ptr<task::TaskData> task = 12232898ceaSJames Feist task::TaskData::createTask( 12332898ceaSJames Feist [](boost::system::error_code ec, 12432898ceaSJames Feist sdbusplus::message::message &msg, 12532898ceaSJames Feist const std::shared_ptr<task::TaskData> 12632898ceaSJames Feist &taskData) { 12732898ceaSJames Feist if (ec) 12832898ceaSJames Feist { 12932898ceaSJames Feist return task::completed; 13032898ceaSJames Feist } 13132898ceaSJames Feist 13232898ceaSJames Feist std::string iface; 13332898ceaSJames Feist boost::container::flat_map< 13432898ceaSJames Feist std::string, std::variant<std::string>> 13532898ceaSJames Feist values; 13632898ceaSJames Feist msg.read(iface, values); 13732898ceaSJames Feist auto findActivation = 13832898ceaSJames Feist values.find("Activation"); 13932898ceaSJames Feist if (findActivation == values.end()) 14032898ceaSJames Feist { 14132898ceaSJames Feist return !task::completed; 14232898ceaSJames Feist } 14332898ceaSJames Feist std::string *state = 14432898ceaSJames Feist std::get_if<std::string>( 14532898ceaSJames Feist &(findActivation->second)); 14632898ceaSJames Feist 14732898ceaSJames Feist if (state == nullptr) 14832898ceaSJames Feist { 14932898ceaSJames Feist taskData->messages.emplace_back( 15032898ceaSJames Feist messages::internalError()); 15132898ceaSJames Feist return task::completed; 15232898ceaSJames Feist } 15332898ceaSJames Feist 154*e5d5006bSJames Feist std::string index = 155*e5d5006bSJames Feist std::to_string(taskData->index); 156*e5d5006bSJames Feist 15732898ceaSJames Feist if (boost::ends_with(*state, "Invalid") || 15832898ceaSJames Feist boost::ends_with(*state, "Failed")) 15932898ceaSJames Feist { 16032898ceaSJames Feist taskData->state = "Exception"; 16132898ceaSJames Feist taskData->status = "Warning"; 16232898ceaSJames Feist taskData->messages.emplace_back( 163*e5d5006bSJames Feist messages::taskAborted(index)); 16432898ceaSJames Feist return task::completed; 16532898ceaSJames Feist } 16632898ceaSJames Feist 16732898ceaSJames Feist if (boost::ends_with(*state, "Staged")) 16832898ceaSJames Feist { 16932898ceaSJames Feist taskData->state = "Pending"; 17032898ceaSJames Feist return !task::completed; 17132898ceaSJames Feist } 17232898ceaSJames Feist 17332898ceaSJames Feist if (boost::ends_with(*state, "Active")) 17432898ceaSJames Feist { 17532898ceaSJames Feist taskData->messages.emplace_back( 176*e5d5006bSJames Feist messages::taskCompletedOK(index)); 17732898ceaSJames Feist taskData->state = "Completed"; 17832898ceaSJames Feist return task::completed; 17932898ceaSJames Feist } 18032898ceaSJames Feist 18132898ceaSJames Feist // as firmware update often results in a 18232898ceaSJames Feist // reboot, the task may never "complete" 18332898ceaSJames Feist // unless it is an error 18432898ceaSJames Feist 18532898ceaSJames Feist return !task::completed; 18632898ceaSJames Feist }, 18732898ceaSJames Feist "type='signal',interface='org.freedesktop.DBus." 18832898ceaSJames Feist "Properties'," 18932898ceaSJames Feist "member='PropertiesChanged',arg0='xyz.openbmc_" 19032898ceaSJames Feist "project.Software.Activation',path='" + 19132898ceaSJames Feist objPath.str + "'"); 19232898ceaSJames Feist task->startTimer(std::chrono::minutes(5)); 19332898ceaSJames Feist task->populateResp(asyncResp->res); 194fe306728SJames Feist task->payload.emplace(req); 1950554c984SAndrew Geissler } 19686adcd6dSAndrew Geissler fwUpdateInProgress = false; 19786adcd6dSAndrew Geissler }, 19886adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 19986adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 20086adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 20186adcd6dSAndrew Geissler std::array<const char *, 1>{ 20286adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 20386adcd6dSAndrew Geissler } 20486adcd6dSAndrew Geissler } 20586adcd6dSAndrew Geissler } 20686adcd6dSAndrew Geissler 2070554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 2080554c984SAndrew Geissler // then no asyncResp updates will occur 20986adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 2100554c984SAndrew Geissler const crow::Request &req, 2110554c984SAndrew Geissler int timeoutTimeSeconds = 5) 21286adcd6dSAndrew Geissler { 21386adcd6dSAndrew Geissler // Only allow one FW update at a time 21486adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 21586adcd6dSAndrew Geissler { 2160554c984SAndrew Geissler if (asyncResp) 2170554c984SAndrew Geissler { 21886adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 2190554c984SAndrew Geissler } 22086adcd6dSAndrew Geissler return; 22186adcd6dSAndrew Geissler } 22286adcd6dSAndrew Geissler 2230554c984SAndrew Geissler fwAvailableTimer = 224271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 22586adcd6dSAndrew Geissler 226271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 22786adcd6dSAndrew Geissler 22886adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 22986adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 23086adcd6dSAndrew Geissler cleanUp(); 23186adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 23286adcd6dSAndrew Geissler { 23386adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 23486adcd6dSAndrew Geissler return; 23586adcd6dSAndrew Geissler } 23686adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23786adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 23886adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23986adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 24086adcd6dSAndrew Geissler if (ec) 24186adcd6dSAndrew Geissler { 24286adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 24386adcd6dSAndrew Geissler return; 24486adcd6dSAndrew Geissler } 2450554c984SAndrew Geissler if (asyncResp) 2460554c984SAndrew Geissler { 24786adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 2480554c984SAndrew Geissler } 24986adcd6dSAndrew Geissler }); 25086adcd6dSAndrew Geissler 251fe306728SJames Feist auto callback = [asyncResp, req](sdbusplus::message::message &m) { 25286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 253fe306728SJames Feist softwareInterfaceAdded(asyncResp, m, req); 25486adcd6dSAndrew Geissler }; 25586adcd6dSAndrew Geissler 25686adcd6dSAndrew Geissler fwUpdateInProgress = true; 25786adcd6dSAndrew Geissler 25886adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 25986adcd6dSAndrew Geissler *crow::connections::systemBus, 26086adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 26186adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 26286adcd6dSAndrew Geissler callback); 26386adcd6dSAndrew Geissler } 264729dae72SJennifer Lee 2650554c984SAndrew Geissler /** 2660554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 2670554c984SAndrew Geissler * SimpleUpdate action. 2680554c984SAndrew Geissler */ 2690554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 2700554c984SAndrew Geissler { 2710554c984SAndrew Geissler public: 2720554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 2730554c984SAndrew Geissler Node(app, 2740554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 2750554c984SAndrew Geissler { 2760554c984SAndrew Geissler entityPrivileges = { 2770554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 2780554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 2790554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 2800554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2810554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2820554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2830554c984SAndrew Geissler } 2840554c984SAndrew Geissler 2850554c984SAndrew Geissler private: 2860554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 2870554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 2880554c984SAndrew Geissler { 2890554c984SAndrew Geissler std::optional<std::string> transferProtocol; 2900554c984SAndrew Geissler std::string imageURI; 2910554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2920554c984SAndrew Geissler 2930554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 2940554c984SAndrew Geissler 2950554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 2960554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 2970554c984SAndrew Geissler // within it. 2980554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 2990554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 3000554c984SAndrew Geissler 3010554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 3020554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 3030554c984SAndrew Geissler { 3040554c984SAndrew Geissler BMCWEB_LOG_DEBUG 3050554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 3060554c984SAndrew Geissler return; 3070554c984SAndrew Geissler } 3080554c984SAndrew Geissler if (!transferProtocol) 3090554c984SAndrew Geissler { 3100554c984SAndrew Geissler // Must be option 2 3110554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 3120554c984SAndrew Geissler size_t separator = imageURI.find(":"); 3130554c984SAndrew Geissler if ((separator == std::string::npos) || 3140554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3150554c984SAndrew Geissler { 3160554c984SAndrew Geissler messages::actionParameterValueTypeError( 3170554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3180554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3190554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 3200554c984SAndrew Geissler << imageURI; 3210554c984SAndrew Geissler return; 3220554c984SAndrew Geissler } 3230554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 3240554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 3250554c984SAndrew Geissler boost::to_upper(*transferProtocol); 3260554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 3270554c984SAndrew Geissler << *transferProtocol; 3280554c984SAndrew Geissler 3290554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 3300554c984SAndrew Geissler // below 3310554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 3320554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 3330554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 3340554c984SAndrew Geissler } 3350554c984SAndrew Geissler 3360554c984SAndrew Geissler // OpenBMC currently only supports TFTP 3370554c984SAndrew Geissler if (*transferProtocol != "TFTP") 3380554c984SAndrew Geissler { 3390554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 3400554c984SAndrew Geissler "TransferProtocol", 3410554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3420554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 3430554c984SAndrew Geissler << *transferProtocol; 3440554c984SAndrew Geissler return; 3450554c984SAndrew Geissler } 3460554c984SAndrew Geissler 3470554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 3480554c984SAndrew Geissler size_t separator = imageURI.find("/"); 3490554c984SAndrew Geissler if ((separator == std::string::npos) || 3500554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3510554c984SAndrew Geissler { 3520554c984SAndrew Geissler messages::actionParameterValueTypeError( 3530554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3540554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3550554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 3560554c984SAndrew Geissler return; 3570554c984SAndrew Geissler } 3580554c984SAndrew Geissler 3590554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 3600554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 3610554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 3620554c984SAndrew Geissler 3630554c984SAndrew Geissler // Setup callback for when new software detected 3640554c984SAndrew Geissler // Give TFTP 2 minutes to complete 3650554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 3660554c984SAndrew Geissler 3670554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 3680554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 3690554c984SAndrew Geissler // has been started. The callback above will ensure the activate 3700554c984SAndrew Geissler // is started once the download has completed 3710554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 3720554c984SAndrew Geissler 3730554c984SAndrew Geissler // Call TFTP service 3740554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 3750554c984SAndrew Geissler [](const boost::system::error_code ec) { 3760554c984SAndrew Geissler if (ec) 3770554c984SAndrew Geissler { 3780554c984SAndrew Geissler // messages::internalError(asyncResp->res); 3790554c984SAndrew Geissler cleanUp(); 3800554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 3810554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 3820554c984SAndrew Geissler } 3830554c984SAndrew Geissler else 3840554c984SAndrew Geissler { 3850554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 3860554c984SAndrew Geissler } 3870554c984SAndrew Geissler }, 3880554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 3890554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 3900554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 3910554c984SAndrew Geissler 3920554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 3930554c984SAndrew Geissler } 3940554c984SAndrew Geissler }; 3950554c984SAndrew Geissler 3961abe55efSEd Tanous class UpdateService : public Node 3971abe55efSEd Tanous { 398729dae72SJennifer Lee public: 3991abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 4001abe55efSEd Tanous { 401729dae72SJennifer Lee entityPrivileges = { 402729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 403729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 404729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 405729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 406729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 407729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 408729dae72SJennifer Lee } 409729dae72SJennifer Lee 410729dae72SJennifer Lee private: 41155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 4121abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4131abe55efSEd Tanous { 414274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 415274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 4160f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 4170f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 4180f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 4190f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 4200f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 4210f74e643SEd Tanous // UpdateService cannot be disabled 4220f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 4230f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 4240f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 4250554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 4260554c984SAndrew Geissler // Update Actions object. 4270554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 4280554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 4290554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 4300554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 4310554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 4320554c984SAndrew Geissler "TFTP"}; 4330554c984SAndrew Geissler #endif 434274dfe62SJayashankar Padath // Get the current ApplyTime value 435274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 436274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 437274dfe62SJayashankar Padath const std::variant<std::string> &applyTime) { 438274dfe62SJayashankar Padath if (ec) 439274dfe62SJayashankar Padath { 440274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 441274dfe62SJayashankar Padath messages::internalError(aResp->res); 442274dfe62SJayashankar Padath return; 443274dfe62SJayashankar Padath } 444274dfe62SJayashankar Padath 445274dfe62SJayashankar Padath const std::string *s = std::get_if<std::string>(&applyTime); 446274dfe62SJayashankar Padath if (s == nullptr) 447274dfe62SJayashankar Padath { 448274dfe62SJayashankar Padath return; 449274dfe62SJayashankar Padath } 450274dfe62SJayashankar Padath // Store the ApplyTime Value 451274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 452274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 453274dfe62SJayashankar Padath { 454274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 455274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 456274dfe62SJayashankar Padath "Immediate"; 457274dfe62SJayashankar Padath } 458274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 459274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 460274dfe62SJayashankar Padath { 461274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 462274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 463274dfe62SJayashankar Padath "OnReset"; 464274dfe62SJayashankar Padath } 465274dfe62SJayashankar Padath }, 466274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 467274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 468274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 469274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 470729dae72SJennifer Lee } 4710e7de46fSAndrew Geissler 472fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 473fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 474fa1a5a38SJayashankar Padath { 475fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 476fa1a5a38SJayashankar Padath 477fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 478fa1a5a38SJayashankar Padath 479274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 480274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 481274dfe62SJayashankar Padath pushUriOptions)) 482fa1a5a38SJayashankar Padath { 483fa1a5a38SJayashankar Padath return; 484fa1a5a38SJayashankar Padath } 485fa1a5a38SJayashankar Padath 486274dfe62SJayashankar Padath if (pushUriOptions) 487274dfe62SJayashankar Padath { 488274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 489274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 490274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 491274dfe62SJayashankar Padath { 492274dfe62SJayashankar Padath return; 493274dfe62SJayashankar Padath } 494274dfe62SJayashankar Padath 495274dfe62SJayashankar Padath if (pushUriApplyTime) 496274dfe62SJayashankar Padath { 497274dfe62SJayashankar Padath std::optional<std::string> applyTime; 498274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 499274dfe62SJayashankar Padath applyTime)) 500274dfe62SJayashankar Padath { 501274dfe62SJayashankar Padath return; 502274dfe62SJayashankar Padath } 503274dfe62SJayashankar Padath 504274dfe62SJayashankar Padath if (applyTime) 505fa1a5a38SJayashankar Padath { 506fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 507fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 508fa1a5a38SJayashankar Padath { 509274dfe62SJayashankar Padath applyTimeNewVal = 510274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 511fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 512fa1a5a38SJayashankar Padath } 513274dfe62SJayashankar Padath else if (applyTime == "OnReset") 514274dfe62SJayashankar Padath { 515274dfe62SJayashankar Padath applyTimeNewVal = 516274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 517274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 518274dfe62SJayashankar Padath } 519fa1a5a38SJayashankar Padath else 520fa1a5a38SJayashankar Padath { 521274dfe62SJayashankar Padath BMCWEB_LOG_INFO 522274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 523274dfe62SJayashankar Padath "acceptable values"; 524274dfe62SJayashankar Padath messages::propertyValueNotInList( 525274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 526274dfe62SJayashankar Padath return; 527fa1a5a38SJayashankar Padath } 528fa1a5a38SJayashankar Padath 529fa1a5a38SJayashankar Padath // Set the requested image apply time value 530fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 531fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 532fa1a5a38SJayashankar Padath if (ec) 533fa1a5a38SJayashankar Padath { 534274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 535274dfe62SJayashankar Padath << ec; 536fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 537fa1a5a38SJayashankar Padath return; 538fa1a5a38SJayashankar Padath } 539fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 540fa1a5a38SJayashankar Padath }, 541fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 542fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 543fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 544274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 545274dfe62SJayashankar Padath "RequestedApplyTime", 546fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 547fa1a5a38SJayashankar Padath } 548274dfe62SJayashankar Padath } 549fa1a5a38SJayashankar Padath } 550fa1a5a38SJayashankar Padath } 551fa1a5a38SJayashankar Padath 552acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 5531abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5541abe55efSEd Tanous { 555acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 556acb7cfb4SJennifer Lee 5570e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 558acb7cfb4SJennifer Lee 55986adcd6dSAndrew Geissler // Setup callback for when new software detected 56086adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 561acb7cfb4SJennifer Lee 562acb7cfb4SJennifer Lee std::string filepath( 563acb7cfb4SJennifer Lee "/tmp/images/" + 564acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 565acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 566acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 567acb7cfb4SJennifer Lee std::ofstream::trunc); 568acb7cfb4SJennifer Lee out << req.body; 569acb7cfb4SJennifer Lee out.close(); 570acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 571acb7cfb4SJennifer Lee } 572729dae72SJennifer Lee }; 573729dae72SJennifer Lee 5741abe55efSEd Tanous class SoftwareInventoryCollection : public Node 5751abe55efSEd Tanous { 576729dae72SJennifer Lee public: 577729dae72SJennifer Lee template <typename CrowApp> 5781abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 5791abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 5801abe55efSEd Tanous { 581729dae72SJennifer Lee entityPrivileges = { 582729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 583729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 584729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 585729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 586729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 587729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 588729dae72SJennifer Lee } 589729dae72SJennifer Lee 590729dae72SJennifer Lee private: 59155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 5921abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5931abe55efSEd Tanous { 594c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 5950f74e643SEd Tanous res.jsonValue["@odata.type"] = 5960f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 5970f74e643SEd Tanous res.jsonValue["@odata.id"] = 5980f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 5990f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 600c711bf86SEd Tanous 601c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 602c711bf86SEd Tanous [asyncResp]( 603c711bf86SEd Tanous const boost::system::error_code ec, 6046c4eb9deSJennifer Lee const std::vector<std::pair< 6051abe55efSEd Tanous std::string, std::vector<std::pair< 6061abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6076c4eb9deSJennifer Lee &subtree) { 6081abe55efSEd Tanous if (ec) 6091abe55efSEd Tanous { 610f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6116c4eb9deSJennifer Lee return; 612729dae72SJennifer Lee } 613c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 614c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 6156c4eb9deSJennifer Lee 6161abe55efSEd Tanous for (auto &obj : subtree) 6171abe55efSEd Tanous { 618f4b65ab1SJennifer Lee // if can't parse fw id then return 61927826b5fSEd Tanous std::size_t idPos; 62027826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 621f4b65ab1SJennifer Lee { 622f12894f8SJason M. Bills messages::internalError(asyncResp->res); 623f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 624f4b65ab1SJennifer Lee return; 625f4b65ab1SJennifer Lee } 626f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 627f4b65ab1SJennifer Lee 628c711bf86SEd Tanous nlohmann::json &members = 629c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 630c711bf86SEd Tanous members.push_back( 631f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 6321abe55efSEd Tanous "FirmwareInventory/" + 633f4b65ab1SJennifer Lee swId}}); 634e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 635c711bf86SEd Tanous members.size(); 6366c4eb9deSJennifer Lee } 637c711bf86SEd Tanous }, 6382830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 6392830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 6402830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 6412830a9cfSAndrew Geissler // path must be used here as input to mapper 642c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 643c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 6442830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6452830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 6461abe55efSEd Tanous std::array<const char *, 1>{ 6471abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 648729dae72SJennifer Lee } 649729dae72SJennifer Lee }; 650c711bf86SEd Tanous 6511abe55efSEd Tanous class SoftwareInventory : public Node 6521abe55efSEd Tanous { 653729dae72SJennifer Lee public: 654729dae72SJennifer Lee template <typename CrowApp> 6551abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 6561abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 6571abe55efSEd Tanous std::string()) 6581abe55efSEd Tanous { 659729dae72SJennifer Lee entityPrivileges = { 660729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 661729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 662729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 663729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 664729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 665729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 666729dae72SJennifer Lee } 667729dae72SJennifer Lee 668729dae72SJennifer Lee private: 66987d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 67087d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 67187d84729SAndrew Geissler const std::string &purpose) 67287d84729SAndrew Geissler { 67387d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 67487d84729SAndrew Geissler { 67587d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 67687d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 67787d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 67887d84729SAndrew Geissler } 67987d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 68087d84729SAndrew Geissler { 681f723d733SGunnar Mills nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 682f723d733SGunnar Mills members.push_back( 683f723d733SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system/Bios"}}); 684f723d733SGunnar Mills aResp->res.jsonValue["Members@odata.count"] = members.size(); 68587d84729SAndrew Geissler } 68687d84729SAndrew Geissler else 68787d84729SAndrew Geissler { 68887d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 68987d84729SAndrew Geissler } 69087d84729SAndrew Geissler } 69187d84729SAndrew Geissler 69255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6931abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6941abe55efSEd Tanous { 695c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6966c4eb9deSJennifer Lee 6971abe55efSEd Tanous if (params.size() != 1) 6981abe55efSEd Tanous { 699f12894f8SJason M. Bills messages::internalError(res); 700729dae72SJennifer Lee res.end(); 701729dae72SJennifer Lee return; 702729dae72SJennifer Lee } 703729dae72SJennifer Lee 7043ae837c9SEd Tanous std::shared_ptr<std::string> swId = 705c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 706c711bf86SEd Tanous 70755c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 7083ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 709c711bf86SEd Tanous 710c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 7113ae837c9SEd Tanous [asyncResp, swId]( 712c711bf86SEd Tanous const boost::system::error_code ec, 7136c4eb9deSJennifer Lee const std::vector<std::pair< 7141abe55efSEd Tanous std::string, std::vector<std::pair< 7151abe55efSEd Tanous std::string, std::vector<std::string>>>>> 7166c4eb9deSJennifer Lee &subtree) { 71755c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 7181abe55efSEd Tanous if (ec) 7191abe55efSEd Tanous { 720f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7216c4eb9deSJennifer Lee return; 7226c4eb9deSJennifer Lee } 7236c4eb9deSJennifer Lee 7246913228dSAndrew Geissler // Ensure we find our input swId, otherwise return an error 7256913228dSAndrew Geissler bool found = false; 7261abe55efSEd Tanous for (const std::pair< 7271abe55efSEd Tanous std::string, 7281abe55efSEd Tanous std::vector< 7291abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 7301abe55efSEd Tanous &obj : subtree) 7311abe55efSEd Tanous { 7323ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 7331abe55efSEd Tanous { 734acb7cfb4SJennifer Lee continue; 735acb7cfb4SJennifer Lee } 736acb7cfb4SJennifer Lee 737f4b65ab1SJennifer Lee if (obj.second.size() < 1) 7381abe55efSEd Tanous { 739acb7cfb4SJennifer Lee continue; 740acb7cfb4SJennifer Lee } 7416c4eb9deSJennifer Lee 7426913228dSAndrew Geissler found = true; 743e0dd8057SAndrew Geissler fw_util::getFwStatus(asyncResp, swId, obj.second[0].first); 744e0dd8057SAndrew Geissler 74555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7461abe55efSEd Tanous [asyncResp, 7473ae837c9SEd Tanous swId](const boost::system::error_code error_code, 7481abe55efSEd Tanous const boost::container::flat_map< 7491abe55efSEd Tanous std::string, VariantType> &propertiesList) { 7501abe55efSEd Tanous if (error_code) 7511abe55efSEd Tanous { 752f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7536c4eb9deSJennifer Lee return; 7546c4eb9deSJennifer Lee } 7551abe55efSEd Tanous boost::container::flat_map< 7561abe55efSEd Tanous std::string, VariantType>::const_iterator it = 7576c4eb9deSJennifer Lee propertiesList.find("Purpose"); 7581abe55efSEd Tanous if (it == propertiesList.end()) 7591abe55efSEd Tanous { 7601abe55efSEd Tanous BMCWEB_LOG_DEBUG 7611abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 762f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 763f12894f8SJason M. Bills "Purpose"); 7646c4eb9deSJennifer Lee return; 7656c4eb9deSJennifer Lee } 7663ae837c9SEd Tanous const std::string *swInvPurpose = 767abf2add6SEd Tanous std::get_if<std::string>(&it->second); 7683ae837c9SEd Tanous if (swInvPurpose == nullptr) 7691abe55efSEd Tanous { 7701abe55efSEd Tanous BMCWEB_LOG_DEBUG 7711abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 772f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 773f12894f8SJason M. Bills "", "Purpose"); 774acb7cfb4SJennifer Lee return; 775acb7cfb4SJennifer Lee } 776c711bf86SEd Tanous 7773ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 7783ae837c9SEd Tanous << *swInvPurpose; 779c711bf86SEd Tanous it = propertiesList.find("Version"); 7801abe55efSEd Tanous if (it == propertiesList.end()) 7811abe55efSEd Tanous { 7821abe55efSEd Tanous BMCWEB_LOG_DEBUG 7831abe55efSEd Tanous << "Can't find property \"Version\"!"; 784f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 785f12894f8SJason M. Bills "Version"); 786c711bf86SEd Tanous return; 787acb7cfb4SJennifer Lee } 788acb7cfb4SJennifer Lee 789f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 790c711bf86SEd Tanous 791f4b65ab1SJennifer Lee const std::string *version = 792abf2add6SEd Tanous std::get_if<std::string>(&it->second); 793f4b65ab1SJennifer Lee 794f4b65ab1SJennifer Lee if (version == nullptr) 7951abe55efSEd Tanous { 7961abe55efSEd Tanous BMCWEB_LOG_DEBUG 7971abe55efSEd Tanous << "Can't find property \"Version\"!"; 798f12894f8SJason M. Bills 799f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 800f12894f8SJason M. Bills "", "Version"); 8016c4eb9deSJennifer Lee return; 8026c4eb9deSJennifer Lee } 803c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 8043ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 80554daabe7SAndrew Geissler 80654daabe7SAndrew Geissler // swInvPurpose is of format: 80754daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 808e2e96770SJames Feist // Translate this to "ABC image" 80954daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 81054daabe7SAndrew Geissler if (endDesc == std::string::npos) 81154daabe7SAndrew Geissler { 81254daabe7SAndrew Geissler messages::internalError(asyncResp->res); 81354daabe7SAndrew Geissler return; 81454daabe7SAndrew Geissler } 81554daabe7SAndrew Geissler endDesc++; 81654daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 81754daabe7SAndrew Geissler { 81854daabe7SAndrew Geissler messages::internalError(asyncResp->res); 81954daabe7SAndrew Geissler return; 82054daabe7SAndrew Geissler } 82154daabe7SAndrew Geissler 82254daabe7SAndrew Geissler std::string formatDesc = 82354daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 82454daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 825e2e96770SJames Feist formatDesc + " image"; 82687d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 8276c4eb9deSJennifer Lee }, 828c711bf86SEd Tanous obj.second[0].first, obj.first, 829c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 830c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 8316c4eb9deSJennifer Lee } 8326913228dSAndrew Geissler if (!found) 8336913228dSAndrew Geissler { 8346913228dSAndrew Geissler BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!"; 8356913228dSAndrew Geissler messages::resourceMissingAtURI( 8366913228dSAndrew Geissler asyncResp->res, 8376913228dSAndrew Geissler "/redfish/v1/UpdateService/FirmwareInventory/" + *swId); 8386913228dSAndrew Geissler return; 8396913228dSAndrew Geissler } 8404e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.type"] = 8414e68c45bSAyushi Smriti "#SoftwareInventory.v1_1_0.SoftwareInventory"; 8424e68c45bSAyushi Smriti asyncResp->res.jsonValue["Name"] = "Software Inventory"; 8434e68c45bSAyushi Smriti asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK"; 8443f8a743aSAppaRao Puli 8453f8a743aSAppaRao Puli asyncResp->res.jsonValue["Updateable"] = false; 8463f8a743aSAppaRao Puli fw_util::getFwUpdateableStatus(asyncResp, swId); 847c711bf86SEd Tanous }, 848c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 849c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 850271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 851271584abSEd Tanous static_cast<int32_t>(0), 8521abe55efSEd Tanous std::array<const char *, 1>{ 8531abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 8546c4eb9deSJennifer Lee } 855729dae72SJennifer Lee }; 856729dae72SJennifer Lee 857729dae72SJennifer Lee } // namespace redfish 858