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, 61*fe306728SJames Feist sdbusplus::message::message &m, 62*fe306728SJames 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( 85*fe306728SJames Feist [objPath, asyncResp, 86*fe306728SJames 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 15432898ceaSJames Feist if (boost::ends_with(*state, "Invalid") || 15532898ceaSJames Feist boost::ends_with(*state, "Failed")) 15632898ceaSJames Feist { 15732898ceaSJames Feist taskData->state = "Exception"; 15832898ceaSJames Feist taskData->status = "Warning"; 15932898ceaSJames Feist taskData->messages.emplace_back( 16032898ceaSJames Feist messages::invalidObject( 16132898ceaSJames Feist "/redfish/v1/UpdateService/")); 16232898ceaSJames Feist return task::completed; 16332898ceaSJames Feist } 16432898ceaSJames Feist 16532898ceaSJames Feist if (boost::ends_with(*state, "Staged")) 16632898ceaSJames Feist { 16732898ceaSJames Feist taskData->state = "Pending"; 16832898ceaSJames Feist return !task::completed; 16932898ceaSJames Feist } 17032898ceaSJames Feist 17132898ceaSJames Feist if (boost::ends_with(*state, "Active")) 17232898ceaSJames Feist { 17332898ceaSJames Feist taskData->messages.emplace_back( 17432898ceaSJames Feist messages::success()); 17532898ceaSJames Feist taskData->state = "Completed"; 17632898ceaSJames Feist return task::completed; 17732898ceaSJames Feist } 17832898ceaSJames Feist 17932898ceaSJames Feist // as firmware update often results in a 18032898ceaSJames Feist // reboot, the task may never "complete" 18132898ceaSJames Feist // unless it is an error 18232898ceaSJames Feist 18332898ceaSJames Feist return !task::completed; 18432898ceaSJames Feist }, 18532898ceaSJames Feist "type='signal',interface='org.freedesktop.DBus." 18632898ceaSJames Feist "Properties'," 18732898ceaSJames Feist "member='PropertiesChanged',arg0='xyz.openbmc_" 18832898ceaSJames Feist "project.Software.Activation',path='" + 18932898ceaSJames Feist objPath.str + "'"); 19032898ceaSJames Feist task->startTimer(std::chrono::minutes(5)); 19132898ceaSJames Feist task->populateResp(asyncResp->res); 192*fe306728SJames Feist task->payload.emplace(req); 1930554c984SAndrew Geissler } 19486adcd6dSAndrew Geissler fwUpdateInProgress = false; 19586adcd6dSAndrew Geissler }, 19686adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 19786adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 19886adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 19986adcd6dSAndrew Geissler std::array<const char *, 1>{ 20086adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 20186adcd6dSAndrew Geissler } 20286adcd6dSAndrew Geissler } 20386adcd6dSAndrew Geissler } 20486adcd6dSAndrew Geissler 2050554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 2060554c984SAndrew Geissler // then no asyncResp updates will occur 20786adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 2080554c984SAndrew Geissler const crow::Request &req, 2090554c984SAndrew Geissler int timeoutTimeSeconds = 5) 21086adcd6dSAndrew Geissler { 21186adcd6dSAndrew Geissler // Only allow one FW update at a time 21286adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 21386adcd6dSAndrew Geissler { 2140554c984SAndrew Geissler if (asyncResp) 2150554c984SAndrew Geissler { 21686adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 2170554c984SAndrew Geissler } 21886adcd6dSAndrew Geissler return; 21986adcd6dSAndrew Geissler } 22086adcd6dSAndrew Geissler 2210554c984SAndrew Geissler fwAvailableTimer = 222271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 22386adcd6dSAndrew Geissler 224271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 22586adcd6dSAndrew Geissler 22686adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 22786adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 22886adcd6dSAndrew Geissler cleanUp(); 22986adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 23086adcd6dSAndrew Geissler { 23186adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 23286adcd6dSAndrew Geissler return; 23386adcd6dSAndrew Geissler } 23486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23586adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 23686adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23786adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 23886adcd6dSAndrew Geissler if (ec) 23986adcd6dSAndrew Geissler { 24086adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 24186adcd6dSAndrew Geissler return; 24286adcd6dSAndrew Geissler } 2430554c984SAndrew Geissler if (asyncResp) 2440554c984SAndrew Geissler { 24586adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 2460554c984SAndrew Geissler } 24786adcd6dSAndrew Geissler }); 24886adcd6dSAndrew Geissler 249*fe306728SJames Feist auto callback = [asyncResp, req](sdbusplus::message::message &m) { 25086adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 251*fe306728SJames Feist softwareInterfaceAdded(asyncResp, m, req); 25286adcd6dSAndrew Geissler }; 25386adcd6dSAndrew Geissler 25486adcd6dSAndrew Geissler fwUpdateInProgress = true; 25586adcd6dSAndrew Geissler 25686adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 25786adcd6dSAndrew Geissler *crow::connections::systemBus, 25886adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 25986adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 26086adcd6dSAndrew Geissler callback); 26186adcd6dSAndrew Geissler } 262729dae72SJennifer Lee 2630554c984SAndrew Geissler /** 2640554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 2650554c984SAndrew Geissler * SimpleUpdate action. 2660554c984SAndrew Geissler */ 2670554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 2680554c984SAndrew Geissler { 2690554c984SAndrew Geissler public: 2700554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 2710554c984SAndrew Geissler Node(app, 2720554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 2730554c984SAndrew Geissler { 2740554c984SAndrew Geissler entityPrivileges = { 2750554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 2760554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 2770554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 2780554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2790554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2800554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2810554c984SAndrew Geissler } 2820554c984SAndrew Geissler 2830554c984SAndrew Geissler private: 2840554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 2850554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 2860554c984SAndrew Geissler { 2870554c984SAndrew Geissler std::optional<std::string> transferProtocol; 2880554c984SAndrew Geissler std::string imageURI; 2890554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2900554c984SAndrew Geissler 2910554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 2920554c984SAndrew Geissler 2930554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 2940554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 2950554c984SAndrew Geissler // within it. 2960554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 2970554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 2980554c984SAndrew Geissler 2990554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 3000554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 3010554c984SAndrew Geissler { 3020554c984SAndrew Geissler BMCWEB_LOG_DEBUG 3030554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 3040554c984SAndrew Geissler return; 3050554c984SAndrew Geissler } 3060554c984SAndrew Geissler if (!transferProtocol) 3070554c984SAndrew Geissler { 3080554c984SAndrew Geissler // Must be option 2 3090554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 3100554c984SAndrew Geissler size_t separator = imageURI.find(":"); 3110554c984SAndrew Geissler if ((separator == std::string::npos) || 3120554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3130554c984SAndrew Geissler { 3140554c984SAndrew Geissler messages::actionParameterValueTypeError( 3150554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3160554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3170554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 3180554c984SAndrew Geissler << imageURI; 3190554c984SAndrew Geissler return; 3200554c984SAndrew Geissler } 3210554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 3220554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 3230554c984SAndrew Geissler boost::to_upper(*transferProtocol); 3240554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 3250554c984SAndrew Geissler << *transferProtocol; 3260554c984SAndrew Geissler 3270554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 3280554c984SAndrew Geissler // below 3290554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 3300554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 3310554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 3320554c984SAndrew Geissler } 3330554c984SAndrew Geissler 3340554c984SAndrew Geissler // OpenBMC currently only supports TFTP 3350554c984SAndrew Geissler if (*transferProtocol != "TFTP") 3360554c984SAndrew Geissler { 3370554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 3380554c984SAndrew Geissler "TransferProtocol", 3390554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3400554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 3410554c984SAndrew Geissler << *transferProtocol; 3420554c984SAndrew Geissler return; 3430554c984SAndrew Geissler } 3440554c984SAndrew Geissler 3450554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 3460554c984SAndrew Geissler size_t separator = imageURI.find("/"); 3470554c984SAndrew Geissler if ((separator == std::string::npos) || 3480554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3490554c984SAndrew Geissler { 3500554c984SAndrew Geissler messages::actionParameterValueTypeError( 3510554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3520554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3530554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 3540554c984SAndrew Geissler return; 3550554c984SAndrew Geissler } 3560554c984SAndrew Geissler 3570554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 3580554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 3590554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 3600554c984SAndrew Geissler 3610554c984SAndrew Geissler // Setup callback for when new software detected 3620554c984SAndrew Geissler // Give TFTP 2 minutes to complete 3630554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 3640554c984SAndrew Geissler 3650554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 3660554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 3670554c984SAndrew Geissler // has been started. The callback above will ensure the activate 3680554c984SAndrew Geissler // is started once the download has completed 3690554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 3700554c984SAndrew Geissler 3710554c984SAndrew Geissler // Call TFTP service 3720554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 3730554c984SAndrew Geissler [](const boost::system::error_code ec) { 3740554c984SAndrew Geissler if (ec) 3750554c984SAndrew Geissler { 3760554c984SAndrew Geissler // messages::internalError(asyncResp->res); 3770554c984SAndrew Geissler cleanUp(); 3780554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 3790554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 3800554c984SAndrew Geissler } 3810554c984SAndrew Geissler else 3820554c984SAndrew Geissler { 3830554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 3840554c984SAndrew Geissler } 3850554c984SAndrew Geissler }, 3860554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 3870554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 3880554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 3890554c984SAndrew Geissler 3900554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 3910554c984SAndrew Geissler } 3920554c984SAndrew Geissler }; 3930554c984SAndrew Geissler 3941abe55efSEd Tanous class UpdateService : public Node 3951abe55efSEd Tanous { 396729dae72SJennifer Lee public: 3971abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 3981abe55efSEd Tanous { 399729dae72SJennifer Lee entityPrivileges = { 400729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 401729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 402729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 403729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 404729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 405729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 406729dae72SJennifer Lee } 407729dae72SJennifer Lee 408729dae72SJennifer Lee private: 40955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 4101abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4111abe55efSEd Tanous { 412274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 413274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 4140f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 4150f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 4160f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 4170f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 4180f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 4190f74e643SEd Tanous // UpdateService cannot be disabled 4200f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 4210f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 4220f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 4230554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 4240554c984SAndrew Geissler // Update Actions object. 4250554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 4260554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 4270554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 4280554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 4290554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 4300554c984SAndrew Geissler "TFTP"}; 4310554c984SAndrew Geissler #endif 432274dfe62SJayashankar Padath // Get the current ApplyTime value 433274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 434274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 435274dfe62SJayashankar Padath const std::variant<std::string> &applyTime) { 436274dfe62SJayashankar Padath if (ec) 437274dfe62SJayashankar Padath { 438274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 439274dfe62SJayashankar Padath messages::internalError(aResp->res); 440274dfe62SJayashankar Padath return; 441274dfe62SJayashankar Padath } 442274dfe62SJayashankar Padath 443274dfe62SJayashankar Padath const std::string *s = std::get_if<std::string>(&applyTime); 444274dfe62SJayashankar Padath if (s == nullptr) 445274dfe62SJayashankar Padath { 446274dfe62SJayashankar Padath return; 447274dfe62SJayashankar Padath } 448274dfe62SJayashankar Padath // Store the ApplyTime Value 449274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 450274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 451274dfe62SJayashankar Padath { 452274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 453274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 454274dfe62SJayashankar Padath "Immediate"; 455274dfe62SJayashankar Padath } 456274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 457274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 458274dfe62SJayashankar Padath { 459274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 460274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 461274dfe62SJayashankar Padath "OnReset"; 462274dfe62SJayashankar Padath } 463274dfe62SJayashankar Padath }, 464274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 465274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 466274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 467274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 468729dae72SJennifer Lee } 4690e7de46fSAndrew Geissler 470fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 471fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 472fa1a5a38SJayashankar Padath { 473fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 474fa1a5a38SJayashankar Padath 475fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 476fa1a5a38SJayashankar Padath 477274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 478274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 479274dfe62SJayashankar Padath pushUriOptions)) 480fa1a5a38SJayashankar Padath { 481fa1a5a38SJayashankar Padath return; 482fa1a5a38SJayashankar Padath } 483fa1a5a38SJayashankar Padath 484274dfe62SJayashankar Padath if (pushUriOptions) 485274dfe62SJayashankar Padath { 486274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 487274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 488274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 489274dfe62SJayashankar Padath { 490274dfe62SJayashankar Padath return; 491274dfe62SJayashankar Padath } 492274dfe62SJayashankar Padath 493274dfe62SJayashankar Padath if (pushUriApplyTime) 494274dfe62SJayashankar Padath { 495274dfe62SJayashankar Padath std::optional<std::string> applyTime; 496274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 497274dfe62SJayashankar Padath applyTime)) 498274dfe62SJayashankar Padath { 499274dfe62SJayashankar Padath return; 500274dfe62SJayashankar Padath } 501274dfe62SJayashankar Padath 502274dfe62SJayashankar Padath if (applyTime) 503fa1a5a38SJayashankar Padath { 504fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 505fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 506fa1a5a38SJayashankar Padath { 507274dfe62SJayashankar Padath applyTimeNewVal = 508274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 509fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 510fa1a5a38SJayashankar Padath } 511274dfe62SJayashankar Padath else if (applyTime == "OnReset") 512274dfe62SJayashankar Padath { 513274dfe62SJayashankar Padath applyTimeNewVal = 514274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 515274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 516274dfe62SJayashankar Padath } 517fa1a5a38SJayashankar Padath else 518fa1a5a38SJayashankar Padath { 519274dfe62SJayashankar Padath BMCWEB_LOG_INFO 520274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 521274dfe62SJayashankar Padath "acceptable values"; 522274dfe62SJayashankar Padath messages::propertyValueNotInList( 523274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 524274dfe62SJayashankar Padath return; 525fa1a5a38SJayashankar Padath } 526fa1a5a38SJayashankar Padath 527fa1a5a38SJayashankar Padath // Set the requested image apply time value 528fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 529fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 530fa1a5a38SJayashankar Padath if (ec) 531fa1a5a38SJayashankar Padath { 532274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 533274dfe62SJayashankar Padath << ec; 534fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 535fa1a5a38SJayashankar Padath return; 536fa1a5a38SJayashankar Padath } 537fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 538fa1a5a38SJayashankar Padath }, 539fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 540fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 541fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 542274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 543274dfe62SJayashankar Padath "RequestedApplyTime", 544fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 545fa1a5a38SJayashankar Padath } 546274dfe62SJayashankar Padath } 547fa1a5a38SJayashankar Padath } 548fa1a5a38SJayashankar Padath } 549fa1a5a38SJayashankar Padath 550acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 5511abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5521abe55efSEd Tanous { 553acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 554acb7cfb4SJennifer Lee 5550e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 556acb7cfb4SJennifer Lee 55786adcd6dSAndrew Geissler // Setup callback for when new software detected 55886adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 559acb7cfb4SJennifer Lee 560acb7cfb4SJennifer Lee std::string filepath( 561acb7cfb4SJennifer Lee "/tmp/images/" + 562acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 563acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 564acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 565acb7cfb4SJennifer Lee std::ofstream::trunc); 566acb7cfb4SJennifer Lee out << req.body; 567acb7cfb4SJennifer Lee out.close(); 568acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 569acb7cfb4SJennifer Lee } 570729dae72SJennifer Lee }; 571729dae72SJennifer Lee 5721abe55efSEd Tanous class SoftwareInventoryCollection : public Node 5731abe55efSEd Tanous { 574729dae72SJennifer Lee public: 575729dae72SJennifer Lee template <typename CrowApp> 5761abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 5771abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 5781abe55efSEd Tanous { 579729dae72SJennifer Lee entityPrivileges = { 580729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 581729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 582729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 583729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 584729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 585729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 586729dae72SJennifer Lee } 587729dae72SJennifer Lee 588729dae72SJennifer Lee private: 58955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 5901abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5911abe55efSEd Tanous { 592c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 5930f74e643SEd Tanous res.jsonValue["@odata.type"] = 5940f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 5950f74e643SEd Tanous res.jsonValue["@odata.id"] = 5960f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 5970f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 598c711bf86SEd Tanous 599c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 600c711bf86SEd Tanous [asyncResp]( 601c711bf86SEd Tanous const boost::system::error_code ec, 6026c4eb9deSJennifer Lee const std::vector<std::pair< 6031abe55efSEd Tanous std::string, std::vector<std::pair< 6041abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6056c4eb9deSJennifer Lee &subtree) { 6061abe55efSEd Tanous if (ec) 6071abe55efSEd Tanous { 608f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6096c4eb9deSJennifer Lee return; 610729dae72SJennifer Lee } 611c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 612c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 6136c4eb9deSJennifer Lee 6141abe55efSEd Tanous for (auto &obj : subtree) 6151abe55efSEd Tanous { 616f4b65ab1SJennifer Lee // if can't parse fw id then return 61727826b5fSEd Tanous std::size_t idPos; 61827826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 619f4b65ab1SJennifer Lee { 620f12894f8SJason M. Bills messages::internalError(asyncResp->res); 621f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 622f4b65ab1SJennifer Lee return; 623f4b65ab1SJennifer Lee } 624f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 625f4b65ab1SJennifer Lee 626c711bf86SEd Tanous nlohmann::json &members = 627c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 628c711bf86SEd Tanous members.push_back( 629f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 6301abe55efSEd Tanous "FirmwareInventory/" + 631f4b65ab1SJennifer Lee swId}}); 632e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 633c711bf86SEd Tanous members.size(); 6346c4eb9deSJennifer Lee } 635c711bf86SEd Tanous }, 6362830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 6372830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 6382830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 6392830a9cfSAndrew Geissler // path must be used here as input to mapper 640c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 641c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 6422830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6432830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 6441abe55efSEd Tanous std::array<const char *, 1>{ 6451abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 646729dae72SJennifer Lee } 647729dae72SJennifer Lee }; 648c711bf86SEd Tanous 6491abe55efSEd Tanous class SoftwareInventory : public Node 6501abe55efSEd Tanous { 651729dae72SJennifer Lee public: 652729dae72SJennifer Lee template <typename CrowApp> 6531abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 6541abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 6551abe55efSEd Tanous std::string()) 6561abe55efSEd Tanous { 657729dae72SJennifer Lee entityPrivileges = { 658729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 659729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 660729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 661729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 662729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 663729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 664729dae72SJennifer Lee } 665729dae72SJennifer Lee 666729dae72SJennifer Lee private: 66787d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 66887d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 66987d84729SAndrew Geissler const std::string &purpose) 67087d84729SAndrew Geissler { 67187d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 67287d84729SAndrew Geissler { 67387d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 67487d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 67587d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 67687d84729SAndrew Geissler } 67787d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 67887d84729SAndrew Geissler { 679f723d733SGunnar Mills nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 680f723d733SGunnar Mills members.push_back( 681f723d733SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system/Bios"}}); 682f723d733SGunnar Mills aResp->res.jsonValue["Members@odata.count"] = members.size(); 68387d84729SAndrew Geissler } 68487d84729SAndrew Geissler else 68587d84729SAndrew Geissler { 68687d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 68787d84729SAndrew Geissler } 68887d84729SAndrew Geissler } 68987d84729SAndrew Geissler 69055c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6911abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6921abe55efSEd Tanous { 693c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6946c4eb9deSJennifer Lee 6951abe55efSEd Tanous if (params.size() != 1) 6961abe55efSEd Tanous { 697f12894f8SJason M. Bills messages::internalError(res); 698729dae72SJennifer Lee res.end(); 699729dae72SJennifer Lee return; 700729dae72SJennifer Lee } 701729dae72SJennifer Lee 7023ae837c9SEd Tanous std::shared_ptr<std::string> swId = 703c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 704c711bf86SEd Tanous 70555c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 7063ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 707c711bf86SEd Tanous 708c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 7093ae837c9SEd Tanous [asyncResp, swId]( 710c711bf86SEd Tanous const boost::system::error_code ec, 7116c4eb9deSJennifer Lee const std::vector<std::pair< 7121abe55efSEd Tanous std::string, std::vector<std::pair< 7131abe55efSEd Tanous std::string, std::vector<std::string>>>>> 7146c4eb9deSJennifer Lee &subtree) { 71555c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 7161abe55efSEd Tanous if (ec) 7171abe55efSEd Tanous { 718f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7196c4eb9deSJennifer Lee return; 7206c4eb9deSJennifer Lee } 7216c4eb9deSJennifer Lee 7226913228dSAndrew Geissler // Ensure we find our input swId, otherwise return an error 7236913228dSAndrew Geissler bool found = false; 7241abe55efSEd Tanous for (const std::pair< 7251abe55efSEd Tanous std::string, 7261abe55efSEd Tanous std::vector< 7271abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 7281abe55efSEd Tanous &obj : subtree) 7291abe55efSEd Tanous { 7303ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 7311abe55efSEd Tanous { 732acb7cfb4SJennifer Lee continue; 733acb7cfb4SJennifer Lee } 734acb7cfb4SJennifer Lee 735f4b65ab1SJennifer Lee if (obj.second.size() < 1) 7361abe55efSEd Tanous { 737acb7cfb4SJennifer Lee continue; 738acb7cfb4SJennifer Lee } 7396c4eb9deSJennifer Lee 7406913228dSAndrew Geissler found = true; 741e0dd8057SAndrew Geissler fw_util::getFwStatus(asyncResp, swId, obj.second[0].first); 742e0dd8057SAndrew Geissler 74355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7441abe55efSEd Tanous [asyncResp, 7453ae837c9SEd Tanous swId](const boost::system::error_code error_code, 7461abe55efSEd Tanous const boost::container::flat_map< 7471abe55efSEd Tanous std::string, VariantType> &propertiesList) { 7481abe55efSEd Tanous if (error_code) 7491abe55efSEd Tanous { 750f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7516c4eb9deSJennifer Lee return; 7526c4eb9deSJennifer Lee } 7531abe55efSEd Tanous boost::container::flat_map< 7541abe55efSEd Tanous std::string, VariantType>::const_iterator it = 7556c4eb9deSJennifer Lee propertiesList.find("Purpose"); 7561abe55efSEd Tanous if (it == propertiesList.end()) 7571abe55efSEd Tanous { 7581abe55efSEd Tanous BMCWEB_LOG_DEBUG 7591abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 760f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 761f12894f8SJason M. Bills "Purpose"); 7626c4eb9deSJennifer Lee return; 7636c4eb9deSJennifer Lee } 7643ae837c9SEd Tanous const std::string *swInvPurpose = 765abf2add6SEd Tanous std::get_if<std::string>(&it->second); 7663ae837c9SEd Tanous if (swInvPurpose == nullptr) 7671abe55efSEd Tanous { 7681abe55efSEd Tanous BMCWEB_LOG_DEBUG 7691abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 770f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 771f12894f8SJason M. Bills "", "Purpose"); 772acb7cfb4SJennifer Lee return; 773acb7cfb4SJennifer Lee } 774c711bf86SEd Tanous 7753ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 7763ae837c9SEd Tanous << *swInvPurpose; 777c711bf86SEd Tanous it = propertiesList.find("Version"); 7781abe55efSEd Tanous if (it == propertiesList.end()) 7791abe55efSEd Tanous { 7801abe55efSEd Tanous BMCWEB_LOG_DEBUG 7811abe55efSEd Tanous << "Can't find property \"Version\"!"; 782f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 783f12894f8SJason M. Bills "Version"); 784c711bf86SEd Tanous return; 785acb7cfb4SJennifer Lee } 786acb7cfb4SJennifer Lee 787f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 788c711bf86SEd Tanous 789f4b65ab1SJennifer Lee const std::string *version = 790abf2add6SEd Tanous std::get_if<std::string>(&it->second); 791f4b65ab1SJennifer Lee 792f4b65ab1SJennifer Lee if (version == nullptr) 7931abe55efSEd Tanous { 7941abe55efSEd Tanous BMCWEB_LOG_DEBUG 7951abe55efSEd Tanous << "Can't find property \"Version\"!"; 796f12894f8SJason M. Bills 797f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 798f12894f8SJason M. Bills "", "Version"); 7996c4eb9deSJennifer Lee return; 8006c4eb9deSJennifer Lee } 801c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 8023ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 80354daabe7SAndrew Geissler 80454daabe7SAndrew Geissler // swInvPurpose is of format: 80554daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 806e2e96770SJames Feist // Translate this to "ABC image" 80754daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 80854daabe7SAndrew Geissler if (endDesc == std::string::npos) 80954daabe7SAndrew Geissler { 81054daabe7SAndrew Geissler messages::internalError(asyncResp->res); 81154daabe7SAndrew Geissler return; 81254daabe7SAndrew Geissler } 81354daabe7SAndrew Geissler endDesc++; 81454daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 81554daabe7SAndrew Geissler { 81654daabe7SAndrew Geissler messages::internalError(asyncResp->res); 81754daabe7SAndrew Geissler return; 81854daabe7SAndrew Geissler } 81954daabe7SAndrew Geissler 82054daabe7SAndrew Geissler std::string formatDesc = 82154daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 82254daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 823e2e96770SJames Feist formatDesc + " image"; 82487d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 8256c4eb9deSJennifer Lee }, 826c711bf86SEd Tanous obj.second[0].first, obj.first, 827c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 828c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 8296c4eb9deSJennifer Lee } 8306913228dSAndrew Geissler if (!found) 8316913228dSAndrew Geissler { 8326913228dSAndrew Geissler BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!"; 8336913228dSAndrew Geissler messages::resourceMissingAtURI( 8346913228dSAndrew Geissler asyncResp->res, 8356913228dSAndrew Geissler "/redfish/v1/UpdateService/FirmwareInventory/" + *swId); 8366913228dSAndrew Geissler return; 8376913228dSAndrew Geissler } 8384e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.type"] = 8394e68c45bSAyushi Smriti "#SoftwareInventory.v1_1_0.SoftwareInventory"; 8404e68c45bSAyushi Smriti asyncResp->res.jsonValue["Name"] = "Software Inventory"; 8414e68c45bSAyushi Smriti asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK"; 8423f8a743aSAppaRao Puli 8433f8a743aSAppaRao Puli asyncResp->res.jsonValue["Updateable"] = false; 8443f8a743aSAppaRao Puli fw_util::getFwUpdateableStatus(asyncResp, swId); 845c711bf86SEd Tanous }, 846c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 847c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 848271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 849271584abSEd Tanous static_cast<int32_t>(0), 8501abe55efSEd Tanous std::array<const char *, 1>{ 8511abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 8526c4eb9deSJennifer Lee } 853729dae72SJennifer Lee }; 854729dae72SJennifer Lee 855729dae72SJennifer Lee } // namespace redfish 856